docs: an RFC-style SPEC.md for the whole product - #44

Merged
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md
Aug 25, 2026
Merged

docs: an RFC-style SPEC.md for the whole product#44
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md

Conversation

@jtomaszewski

@jtomaszewskijtomaszewski commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Adds SPEC.md, a full service specification in the style of RFC-numbered specs: the artifact schema and every enum, the state store and history log, the seven-status lifecycle with its guards, the daemon's discovery/filing/reopen rules, the runner's tool policy and credential hygiene, the chat protocol, re-anchoring, the single GitHub write and auto-send, plus reference algorithms and a conformance checklist. It is written against the code and tests — which win on disagreement — and its Appendix B records the divergences found while writing it (stale CLI version string, README's re-review carryover claim, the CODE_REVIEW.md severity ladder, allowUserComments) rather than resolving them silently. The spec already describes the review history (#42) and the settled-row reopen rule (#43) as landed, so this should merge after those two. README's "How it works" and CLAUDE.md's Architecture section now point at it, with CLAUDE.md carrying the keep-it-true rule: a PR that changes specified behavior updates the spec in the same PR.

🤖 Generated with Claude Code


Open workspace in Conductor

The full service specification — schemas, lifecycle, tool policy, the
send path — precise enough to reimplement cerber from, written against
the code and tests (which win on disagreement; known divergences are
recorded in its Appendix B rather than silently resolved). It already
describes the review history (#42) and the settled-row reopen rule
(#43), so it should land after them. README and CLAUDE.md point at it,
CLAUDE.md with the keep-it-true rule that stops it rotting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an RFC-style SPEC.md intended to normatively describe Cerber’s behavior (artifact schema, lifecycle, daemon, runner/tool policy, API, CLI, and GitHub write boundary), and updates existing documentation to point readers at the spec as the engineering reference.

Changes:

  • Add SPEC.md as a full service specification for Cerber.
  • Link to SPEC.md from README.md in the lifecycle/docs area.
  • Update CLAUDE.md architecture guidance to require keeping the spec in sync with behavior changes.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
SPEC.mdAdds a comprehensive RFC-style specification covering data model, lifecycle, daemon, runner, API, CLI, and security invariants.
README.mdAdds a link and brief explanation positioning SPEC.md vs docs/lifecycle.md.
CLAUDE.mdAdds guidance that behavior changes described by the spec must update SPEC.md (or be recorded as divergences).
Suppressed comments (4)

SPEC.md:1268

  • The HTTP API table says PATCH /api/reviews/:key “stamps settledAt, clears filed”, but the current handler only updates status/verdictRecommendation and doesn’t set settledAt or clear filed (src/server/index.ts:351-379). Either update the route implementation or adjust the spec (and/or record this in Appendix B) so the API contract matches reality.
| `GET /api/reviews/:key` | one artifact | 404 |
| `PATCH /api/reviews/:key` | settle | only `reviewed`/`skipped` accepted (§8.1); stamps `settledAt`, clears `filed` |
| `POST/PATCH/DELETE …/comments[/:id]` | comment CRUD | delete is user-origin only in the UI |

SPEC.md:1607

  • Appendix A maps “§5 state store, history” to src/core/history.ts, but that file does not exist in the current repository. If history is meant to live elsewhere (or isn’t implemented yet), this mapping should be corrected so implementers can actually find the reference code.
| §4 domain model | `src/core/artifact.ts` |
| §5 state store, history | `src/core/state.ts`, `src/core/history.ts` |
| §6 configuration | `src/core/config.ts` |

SPEC.md:1383

  • The CLI section documents a cerber history <pr> command, but the current CLI does not define a history subcommand (see src/cli/index.ts, no .command("history")). If the command is planned but not yet shipped, it should be called out as a divergence / future work; otherwise update the CLI or remove this from the spec.
 and `running` artifacts.
- **`history <pr>`** — prints the review's history (§5.4): one line per
entry with local timestamp, actor, what happened, and the cause; says
plainly when a review predates the history being kept.
- **`list`**, **`export <pr>`** (renders the markdown document; never touches

SPEC.md:379

  • §5.4 specifies history behavior (store re-reads from disk on every save, ignores caller-supplied history, appends derived entries). None of this exists in the current saveArtifact path, which is a straightforward tmp+rename write (src/core/state.ts:18-25) with no pre-read/merge or derived history. The spec should either be rebased onto the implementation that adds this, or softened/flagged as a known divergence so it doesn’t mis-specify current behavior.
**Appended by the store, never by callers.** The save path itself derives and
appends history: it re-reads the file from disk on **every** save — even when
the caller just read it, because two writers share these files and appending
to the caller's copy would drop whatever the other recorded in between — and
**ignores any history the caller hands in**; disk is the only current copy.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadSPEC.md
Comment on lines +187 to +190
| `filed` | FiledInfo \| null | default `null`; never set on a sent artifact |
| `settledAt` | ISO-8601 string \| null | default `null`; when the row was settled — see below |
| `refresh` | RefreshInfo \| null | default `null` |
| `calibration` | Calibration \| null | default `null` |
Comment threadSPEC.md
Comment on lines +192 to +195
| `pendingChat` | PendingChat \| null | default `null` |
| `preChat` | ReviewSnapshot \| null | default `null` |
| `history` | HistoryEntry[] | OPTIONAL, **no default** — absent means the artifact predates history being kept, which surfaces MUST say rather than showing an empty log (§5.4) |

@jtomaszewski
jtomaszewski merged commit 8801bbe into mainAug 25, 2026
3 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.27.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jtomaszewski
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

docs: an RFC-style SPEC.md for the whole product - #44

Merged
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md
Aug 25, 2026
Merged

docs: an RFC-style SPEC.md for the whole product#44
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md

Conversation

@jtomaszewski

@jtomaszewskijtomaszewski commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Adds SPEC.md, a full service specification in the style of RFC-numbered specs: the artifact schema and every enum, the state store and history log, the seven-status lifecycle with its guards, the daemon's discovery/filing/reopen rules, the runner's tool policy and credential hygiene, the chat protocol, re-anchoring, the single GitHub write and auto-send, plus reference algorithms and a conformance checklist. It is written against the code and tests — which win on disagreement — and its Appendix B records the divergences found while writing it (stale CLI version string, README's re-review carryover claim, the CODE_REVIEW.md severity ladder, allowUserComments) rather than resolving them silently. The spec already describes the review history (#42) and the settled-row reopen rule (#43) as landed, so this should merge after those two. README's "How it works" and CLAUDE.md's Architecture section now point at it, with CLAUDE.md carrying the keep-it-true rule: a PR that changes specified behavior updates the spec in the same PR.

🤖 Generated with Claude Code


Open workspace in Conductor

The full service specification — schemas, lifecycle, tool policy, the
send path — precise enough to reimplement cerber from, written against
the code and tests (which win on disagreement; known divergences are
recorded in its Appendix B rather than silently resolved). It already
describes the review history (#42) and the settled-row reopen rule
(#43), so it should land after them. README and CLAUDE.md point at it,
CLAUDE.md with the keep-it-true rule that stops it rotting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an RFC-style SPEC.md intended to normatively describe Cerber’s behavior (artifact schema, lifecycle, daemon, runner/tool policy, API, CLI, and GitHub write boundary), and updates existing documentation to point readers at the spec as the engineering reference.

Changes:

  • Add SPEC.md as a full service specification for Cerber.
  • Link to SPEC.md from README.md in the lifecycle/docs area.
  • Update CLAUDE.md architecture guidance to require keeping the spec in sync with behavior changes.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
SPEC.mdAdds a comprehensive RFC-style specification covering data model, lifecycle, daemon, runner, API, CLI, and security invariants.
README.mdAdds a link and brief explanation positioning SPEC.md vs docs/lifecycle.md.
CLAUDE.mdAdds guidance that behavior changes described by the spec must update SPEC.md (or be recorded as divergences).
Suppressed comments (4)

SPEC.md:1268

  • The HTTP API table says PATCH /api/reviews/:key “stamps settledAt, clears filed”, but the current handler only updates status/verdictRecommendation and doesn’t set settledAt or clear filed (src/server/index.ts:351-379). Either update the route implementation or adjust the spec (and/or record this in Appendix B) so the API contract matches reality.
| `GET /api/reviews/:key` | one artifact | 404 |
| `PATCH /api/reviews/:key` | settle | only `reviewed`/`skipped` accepted (§8.1); stamps `settledAt`, clears `filed` |
| `POST/PATCH/DELETE …/comments[/:id]` | comment CRUD | delete is user-origin only in the UI |

SPEC.md:1607

  • Appendix A maps “§5 state store, history” to src/core/history.ts, but that file does not exist in the current repository. If history is meant to live elsewhere (or isn’t implemented yet), this mapping should be corrected so implementers can actually find the reference code.
| §4 domain model | `src/core/artifact.ts` |
| §5 state store, history | `src/core/state.ts`, `src/core/history.ts` |
| §6 configuration | `src/core/config.ts` |

SPEC.md:1383

  • The CLI section documents a cerber history <pr> command, but the current CLI does not define a history subcommand (see src/cli/index.ts, no .command("history")). If the command is planned but not yet shipped, it should be called out as a divergence / future work; otherwise update the CLI or remove this from the spec.
 and `running` artifacts.
- **`history <pr>`** — prints the review's history (§5.4): one line per
entry with local timestamp, actor, what happened, and the cause; says
plainly when a review predates the history being kept.
- **`list`**, **`export <pr>`** (renders the markdown document; never touches

SPEC.md:379

  • §5.4 specifies history behavior (store re-reads from disk on every save, ignores caller-supplied history, appends derived entries). None of this exists in the current saveArtifact path, which is a straightforward tmp+rename write (src/core/state.ts:18-25) with no pre-read/merge or derived history. The spec should either be rebased onto the implementation that adds this, or softened/flagged as a known divergence so it doesn’t mis-specify current behavior.
**Appended by the store, never by callers.** The save path itself derives and
appends history: it re-reads the file from disk on **every** save — even when
the caller just read it, because two writers share these files and appending
to the caller's copy would drop whatever the other recorded in between — and
**ignores any history the caller hands in**; disk is the only current copy.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadSPEC.md
Comment on lines +187 to +190
| `filed` | FiledInfo \| null | default `null`; never set on a sent artifact |
| `settledAt` | ISO-8601 string \| null | default `null`; when the row was settled — see below |
| `refresh` | RefreshInfo \| null | default `null` |
| `calibration` | Calibration \| null | default `null` |
Comment threadSPEC.md
Comment on lines +192 to +195
| `pendingChat` | PendingChat \| null | default `null` |
| `preChat` | ReviewSnapshot \| null | default `null` |
| `history` | HistoryEntry[] | OPTIONAL, **no default** — absent means the artifact predates history being kept, which surfaces MUST say rather than showing an empty log (§5.4) |

@jtomaszewski
jtomaszewski merged commit 8801bbe into mainAug 25, 2026
3 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.27.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jtomaszewski
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs: an RFC-style SPEC.md for the whole product - #44

Merged
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md
Aug 25, 2026
Merged

docs: an RFC-style SPEC.md for the whole product#44
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md

Conversation

@jtomaszewski

@jtomaszewskijtomaszewski commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Adds SPEC.md, a full service specification in the style of RFC-numbered specs: the artifact schema and every enum, the state store and history log, the seven-status lifecycle with its guards, the daemon's discovery/filing/reopen rules, the runner's tool policy and credential hygiene, the chat protocol, re-anchoring, the single GitHub write and auto-send, plus reference algorithms and a conformance checklist. It is written against the code and tests — which win on disagreement — and its Appendix B records the divergences found while writing it (stale CLI version string, README's re-review carryover claim, the CODE_REVIEW.md severity ladder, allowUserComments) rather than resolving them silently. The spec already describes the review history (#42) and the settled-row reopen rule (#43) as landed, so this should merge after those two. README's "How it works" and CLAUDE.md's Architecture section now point at it, with CLAUDE.md carrying the keep-it-true rule: a PR that changes specified behavior updates the spec in the same PR.

🤖 Generated with Claude Code


Open workspace in Conductor

The full service specification — schemas, lifecycle, tool policy, the
send path — precise enough to reimplement cerber from, written against
the code and tests (which win on disagreement; known divergences are
recorded in its Appendix B rather than silently resolved). It already
describes the review history (#42) and the settled-row reopen rule
(#43), so it should land after them. README and CLAUDE.md point at it,
CLAUDE.md with the keep-it-true rule that stops it rotting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an RFC-style SPEC.md intended to normatively describe Cerber’s behavior (artifact schema, lifecycle, daemon, runner/tool policy, API, CLI, and GitHub write boundary), and updates existing documentation to point readers at the spec as the engineering reference.

Changes:

  • Add SPEC.md as a full service specification for Cerber.
  • Link to SPEC.md from README.md in the lifecycle/docs area.
  • Update CLAUDE.md architecture guidance to require keeping the spec in sync with behavior changes.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
SPEC.mdAdds a comprehensive RFC-style specification covering data model, lifecycle, daemon, runner, API, CLI, and security invariants.
README.mdAdds a link and brief explanation positioning SPEC.md vs docs/lifecycle.md.
CLAUDE.mdAdds guidance that behavior changes described by the spec must update SPEC.md (or be recorded as divergences).
Suppressed comments (4)

SPEC.md:1268

  • The HTTP API table says PATCH /api/reviews/:key “stamps settledAt, clears filed”, but the current handler only updates status/verdictRecommendation and doesn’t set settledAt or clear filed (src/server/index.ts:351-379). Either update the route implementation or adjust the spec (and/or record this in Appendix B) so the API contract matches reality.
| `GET /api/reviews/:key` | one artifact | 404 |
| `PATCH /api/reviews/:key` | settle | only `reviewed`/`skipped` accepted (§8.1); stamps `settledAt`, clears `filed` |
| `POST/PATCH/DELETE …/comments[/:id]` | comment CRUD | delete is user-origin only in the UI |

SPEC.md:1607

  • Appendix A maps “§5 state store, history” to src/core/history.ts, but that file does not exist in the current repository. If history is meant to live elsewhere (or isn’t implemented yet), this mapping should be corrected so implementers can actually find the reference code.
| §4 domain model | `src/core/artifact.ts` |
| §5 state store, history | `src/core/state.ts`, `src/core/history.ts` |
| §6 configuration | `src/core/config.ts` |

SPEC.md:1383

  • The CLI section documents a cerber history <pr> command, but the current CLI does not define a history subcommand (see src/cli/index.ts, no .command("history")). If the command is planned but not yet shipped, it should be called out as a divergence / future work; otherwise update the CLI or remove this from the spec.
 and `running` artifacts.
- **`history <pr>`** — prints the review's history (§5.4): one line per
entry with local timestamp, actor, what happened, and the cause; says
plainly when a review predates the history being kept.
- **`list`**, **`export <pr>`** (renders the markdown document; never touches

SPEC.md:379

  • §5.4 specifies history behavior (store re-reads from disk on every save, ignores caller-supplied history, appends derived entries). None of this exists in the current saveArtifact path, which is a straightforward tmp+rename write (src/core/state.ts:18-25) with no pre-read/merge or derived history. The spec should either be rebased onto the implementation that adds this, or softened/flagged as a known divergence so it doesn’t mis-specify current behavior.
**Appended by the store, never by callers.** The save path itself derives and
appends history: it re-reads the file from disk on **every** save — even when
the caller just read it, because two writers share these files and appending
to the caller's copy would drop whatever the other recorded in between — and
**ignores any history the caller hands in**; disk is the only current copy.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadSPEC.md
Comment on lines +187 to +190
| `filed` | FiledInfo \| null | default `null`; never set on a sent artifact |
| `settledAt` | ISO-8601 string \| null | default `null`; when the row was settled — see below |
| `refresh` | RefreshInfo \| null | default `null` |
| `calibration` | Calibration \| null | default `null` |
Comment threadSPEC.md
Comment on lines +192 to +195
| `pendingChat` | PendingChat \| null | default `null` |
| `preChat` | ReviewSnapshot \| null | default `null` |
| `history` | HistoryEntry[] | OPTIONAL, **no default** — absent means the artifact predates history being kept, which surfaces MUST say rather than showing an empty log (§5.4) |

@jtomaszewski
jtomaszewski merged commit 8801bbe into mainAug 25, 2026
3 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.27.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jtomaszewski
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs: an RFC-style SPEC.md for the whole product - #44

Merged
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md
Aug 25, 2026
Merged

docs: an RFC-style SPEC.md for the whole product#44
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md

Conversation

@jtomaszewski

@jtomaszewskijtomaszewski commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Adds SPEC.md, a full service specification in the style of RFC-numbered specs: the artifact schema and every enum, the state store and history log, the seven-status lifecycle with its guards, the daemon's discovery/filing/reopen rules, the runner's tool policy and credential hygiene, the chat protocol, re-anchoring, the single GitHub write and auto-send, plus reference algorithms and a conformance checklist. It is written against the code and tests — which win on disagreement — and its Appendix B records the divergences found while writing it (stale CLI version string, README's re-review carryover claim, the CODE_REVIEW.md severity ladder, allowUserComments) rather than resolving them silently. The spec already describes the review history (#42) and the settled-row reopen rule (#43) as landed, so this should merge after those two. README's "How it works" and CLAUDE.md's Architecture section now point at it, with CLAUDE.md carrying the keep-it-true rule: a PR that changes specified behavior updates the spec in the same PR.

🤖 Generated with Claude Code


Open workspace in Conductor

The full service specification — schemas, lifecycle, tool policy, the
send path — precise enough to reimplement cerber from, written against
the code and tests (which win on disagreement; known divergences are
recorded in its Appendix B rather than silently resolved). It already
describes the review history (#42) and the settled-row reopen rule
(#43), so it should land after them. README and CLAUDE.md point at it,
CLAUDE.md with the keep-it-true rule that stops it rotting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an RFC-style SPEC.md intended to normatively describe Cerber’s behavior (artifact schema, lifecycle, daemon, runner/tool policy, API, CLI, and GitHub write boundary), and updates existing documentation to point readers at the spec as the engineering reference.

Changes:

  • Add SPEC.md as a full service specification for Cerber.
  • Link to SPEC.md from README.md in the lifecycle/docs area.
  • Update CLAUDE.md architecture guidance to require keeping the spec in sync with behavior changes.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
SPEC.mdAdds a comprehensive RFC-style specification covering data model, lifecycle, daemon, runner, API, CLI, and security invariants.
README.mdAdds a link and brief explanation positioning SPEC.md vs docs/lifecycle.md.
CLAUDE.mdAdds guidance that behavior changes described by the spec must update SPEC.md (or be recorded as divergences).
Suppressed comments (4)

SPEC.md:1268

  • The HTTP API table says PATCH /api/reviews/:key “stamps settledAt, clears filed”, but the current handler only updates status/verdictRecommendation and doesn’t set settledAt or clear filed (src/server/index.ts:351-379). Either update the route implementation or adjust the spec (and/or record this in Appendix B) so the API contract matches reality.
| `GET /api/reviews/:key` | one artifact | 404 |
| `PATCH /api/reviews/:key` | settle | only `reviewed`/`skipped` accepted (§8.1); stamps `settledAt`, clears `filed` |
| `POST/PATCH/DELETE …/comments[/:id]` | comment CRUD | delete is user-origin only in the UI |

SPEC.md:1607

  • Appendix A maps “§5 state store, history” to src/core/history.ts, but that file does not exist in the current repository. If history is meant to live elsewhere (or isn’t implemented yet), this mapping should be corrected so implementers can actually find the reference code.
| §4 domain model | `src/core/artifact.ts` |
| §5 state store, history | `src/core/state.ts`, `src/core/history.ts` |
| §6 configuration | `src/core/config.ts` |

SPEC.md:1383

  • The CLI section documents a cerber history <pr> command, but the current CLI does not define a history subcommand (see src/cli/index.ts, no .command("history")). If the command is planned but not yet shipped, it should be called out as a divergence / future work; otherwise update the CLI or remove this from the spec.
 and `running` artifacts.
- **`history <pr>`** — prints the review's history (§5.4): one line per
entry with local timestamp, actor, what happened, and the cause; says
plainly when a review predates the history being kept.
- **`list`**, **`export <pr>`** (renders the markdown document; never touches

SPEC.md:379

  • §5.4 specifies history behavior (store re-reads from disk on every save, ignores caller-supplied history, appends derived entries). None of this exists in the current saveArtifact path, which is a straightforward tmp+rename write (src/core/state.ts:18-25) with no pre-read/merge or derived history. The spec should either be rebased onto the implementation that adds this, or softened/flagged as a known divergence so it doesn’t mis-specify current behavior.
**Appended by the store, never by callers.** The save path itself derives and
appends history: it re-reads the file from disk on **every** save — even when
the caller just read it, because two writers share these files and appending
to the caller's copy would drop whatever the other recorded in between — and
**ignores any history the caller hands in**; disk is the only current copy.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadSPEC.md
Comment on lines +187 to +190
| `filed` | FiledInfo \| null | default `null`; never set on a sent artifact |
| `settledAt` | ISO-8601 string \| null | default `null`; when the row was settled — see below |
| `refresh` | RefreshInfo \| null | default `null` |
| `calibration` | Calibration \| null | default `null` |
Comment threadSPEC.md
Comment on lines +192 to +195
| `pendingChat` | PendingChat \| null | default `null` |
| `preChat` | ReviewSnapshot \| null | default `null` |
| `history` | HistoryEntry[] | OPTIONAL, **no default** — absent means the artifact predates history being kept, which surfaces MUST say rather than showing an empty log (§5.4) |

@jtomaszewski
jtomaszewski merged commit 8801bbe into mainAug 25, 2026
3 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.27.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jtomaszewski
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

docs: an RFC-style SPEC.md for the whole product - #44

Merged
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md
Aug 25, 2026
Merged

docs: an RFC-style SPEC.md for the whole product#44
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md

Conversation

@jtomaszewski

@jtomaszewskijtomaszewski commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Adds SPEC.md, a full service specification in the style of RFC-numbered specs: the artifact schema and every enum, the state store and history log, the seven-status lifecycle with its guards, the daemon's discovery/filing/reopen rules, the runner's tool policy and credential hygiene, the chat protocol, re-anchoring, the single GitHub write and auto-send, plus reference algorithms and a conformance checklist. It is written against the code and tests — which win on disagreement — and its Appendix B records the divergences found while writing it (stale CLI version string, README's re-review carryover claim, the CODE_REVIEW.md severity ladder, allowUserComments) rather than resolving them silently. The spec already describes the review history (#42) and the settled-row reopen rule (#43) as landed, so this should merge after those two. README's "How it works" and CLAUDE.md's Architecture section now point at it, with CLAUDE.md carrying the keep-it-true rule: a PR that changes specified behavior updates the spec in the same PR.

🤖 Generated with Claude Code


Open workspace in Conductor

The full service specification — schemas, lifecycle, tool policy, the
send path — precise enough to reimplement cerber from, written against
the code and tests (which win on disagreement; known divergences are
recorded in its Appendix B rather than silently resolved). It already
describes the review history (#42) and the settled-row reopen rule
(#43), so it should land after them. README and CLAUDE.md point at it,
CLAUDE.md with the keep-it-true rule that stops it rotting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an RFC-style SPEC.md intended to normatively describe Cerber’s behavior (artifact schema, lifecycle, daemon, runner/tool policy, API, CLI, and GitHub write boundary), and updates existing documentation to point readers at the spec as the engineering reference.

Changes:

  • Add SPEC.md as a full service specification for Cerber.
  • Link to SPEC.md from README.md in the lifecycle/docs area.
  • Update CLAUDE.md architecture guidance to require keeping the spec in sync with behavior changes.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
SPEC.mdAdds a comprehensive RFC-style specification covering data model, lifecycle, daemon, runner, API, CLI, and security invariants.
README.mdAdds a link and brief explanation positioning SPEC.md vs docs/lifecycle.md.
CLAUDE.mdAdds guidance that behavior changes described by the spec must update SPEC.md (or be recorded as divergences).
Suppressed comments (4)

SPEC.md:1268

  • The HTTP API table says PATCH /api/reviews/:key “stamps settledAt, clears filed”, but the current handler only updates status/verdictRecommendation and doesn’t set settledAt or clear filed (src/server/index.ts:351-379). Either update the route implementation or adjust the spec (and/or record this in Appendix B) so the API contract matches reality.
| `GET /api/reviews/:key` | one artifact | 404 |
| `PATCH /api/reviews/:key` | settle | only `reviewed`/`skipped` accepted (§8.1); stamps `settledAt`, clears `filed` |
| `POST/PATCH/DELETE …/comments[/:id]` | comment CRUD | delete is user-origin only in the UI |

SPEC.md:1607

  • Appendix A maps “§5 state store, history” to src/core/history.ts, but that file does not exist in the current repository. If history is meant to live elsewhere (or isn’t implemented yet), this mapping should be corrected so implementers can actually find the reference code.
| §4 domain model | `src/core/artifact.ts` |
| §5 state store, history | `src/core/state.ts`, `src/core/history.ts` |
| §6 configuration | `src/core/config.ts` |

SPEC.md:1383

  • The CLI section documents a cerber history <pr> command, but the current CLI does not define a history subcommand (see src/cli/index.ts, no .command("history")). If the command is planned but not yet shipped, it should be called out as a divergence / future work; otherwise update the CLI or remove this from the spec.
 and `running` artifacts.
- **`history <pr>`** — prints the review's history (§5.4): one line per
entry with local timestamp, actor, what happened, and the cause; says
plainly when a review predates the history being kept.
- **`list`**, **`export <pr>`** (renders the markdown document; never touches

SPEC.md:379

  • §5.4 specifies history behavior (store re-reads from disk on every save, ignores caller-supplied history, appends derived entries). None of this exists in the current saveArtifact path, which is a straightforward tmp+rename write (src/core/state.ts:18-25) with no pre-read/merge or derived history. The spec should either be rebased onto the implementation that adds this, or softened/flagged as a known divergence so it doesn’t mis-specify current behavior.
**Appended by the store, never by callers.** The save path itself derives and
appends history: it re-reads the file from disk on **every** save — even when
the caller just read it, because two writers share these files and appending
to the caller's copy would drop whatever the other recorded in between — and
**ignores any history the caller hands in**; disk is the only current copy.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadSPEC.md
Comment on lines +187 to +190
| `filed` | FiledInfo \| null | default `null`; never set on a sent artifact |
| `settledAt` | ISO-8601 string \| null | default `null`; when the row was settled — see below |
| `refresh` | RefreshInfo \| null | default `null` |
| `calibration` | Calibration \| null | default `null` |
Comment threadSPEC.md
Comment on lines +192 to +195
| `pendingChat` | PendingChat \| null | default `null` |
| `preChat` | ReviewSnapshot \| null | default `null` |
| `history` | HistoryEntry[] | OPTIONAL, **no default** — absent means the artifact predates history being kept, which surfaces MUST say rather than showing an empty log (§5.4) |

@jtomaszewski
jtomaszewski merged commit 8801bbe into mainAug 25, 2026
3 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.27.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jtomaszewski
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs: an RFC-style SPEC.md for the whole product - #44

Merged
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md
Aug 25, 2026
Merged

docs: an RFC-style SPEC.md for the whole product#44
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md

Conversation

@jtomaszewski

@jtomaszewskijtomaszewski commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Adds SPEC.md, a full service specification in the style of RFC-numbered specs: the artifact schema and every enum, the state store and history log, the seven-status lifecycle with its guards, the daemon's discovery/filing/reopen rules, the runner's tool policy and credential hygiene, the chat protocol, re-anchoring, the single GitHub write and auto-send, plus reference algorithms and a conformance checklist. It is written against the code and tests — which win on disagreement — and its Appendix B records the divergences found while writing it (stale CLI version string, README's re-review carryover claim, the CODE_REVIEW.md severity ladder, allowUserComments) rather than resolving them silently. The spec already describes the review history (#42) and the settled-row reopen rule (#43) as landed, so this should merge after those two. README's "How it works" and CLAUDE.md's Architecture section now point at it, with CLAUDE.md carrying the keep-it-true rule: a PR that changes specified behavior updates the spec in the same PR.

🤖 Generated with Claude Code


Open workspace in Conductor

The full service specification — schemas, lifecycle, tool policy, the
send path — precise enough to reimplement cerber from, written against
the code and tests (which win on disagreement; known divergences are
recorded in its Appendix B rather than silently resolved). It already
describes the review history (#42) and the settled-row reopen rule
(#43), so it should land after them. README and CLAUDE.md point at it,
CLAUDE.md with the keep-it-true rule that stops it rotting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an RFC-style SPEC.md intended to normatively describe Cerber’s behavior (artifact schema, lifecycle, daemon, runner/tool policy, API, CLI, and GitHub write boundary), and updates existing documentation to point readers at the spec as the engineering reference.

Changes:

  • Add SPEC.md as a full service specification for Cerber.
  • Link to SPEC.md from README.md in the lifecycle/docs area.
  • Update CLAUDE.md architecture guidance to require keeping the spec in sync with behavior changes.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
SPEC.mdAdds a comprehensive RFC-style specification covering data model, lifecycle, daemon, runner, API, CLI, and security invariants.
README.mdAdds a link and brief explanation positioning SPEC.md vs docs/lifecycle.md.
CLAUDE.mdAdds guidance that behavior changes described by the spec must update SPEC.md (or be recorded as divergences).
Suppressed comments (4)

SPEC.md:1268

  • The HTTP API table says PATCH /api/reviews/:key “stamps settledAt, clears filed”, but the current handler only updates status/verdictRecommendation and doesn’t set settledAt or clear filed (src/server/index.ts:351-379). Either update the route implementation or adjust the spec (and/or record this in Appendix B) so the API contract matches reality.
| `GET /api/reviews/:key` | one artifact | 404 |
| `PATCH /api/reviews/:key` | settle | only `reviewed`/`skipped` accepted (§8.1); stamps `settledAt`, clears `filed` |
| `POST/PATCH/DELETE …/comments[/:id]` | comment CRUD | delete is user-origin only in the UI |

SPEC.md:1607

  • Appendix A maps “§5 state store, history” to src/core/history.ts, but that file does not exist in the current repository. If history is meant to live elsewhere (or isn’t implemented yet), this mapping should be corrected so implementers can actually find the reference code.
| §4 domain model | `src/core/artifact.ts` |
| §5 state store, history | `src/core/state.ts`, `src/core/history.ts` |
| §6 configuration | `src/core/config.ts` |

SPEC.md:1383

  • The CLI section documents a cerber history <pr> command, but the current CLI does not define a history subcommand (see src/cli/index.ts, no .command("history")). If the command is planned but not yet shipped, it should be called out as a divergence / future work; otherwise update the CLI or remove this from the spec.
 and `running` artifacts.
- **`history <pr>`** — prints the review's history (§5.4): one line per
entry with local timestamp, actor, what happened, and the cause; says
plainly when a review predates the history being kept.
- **`list`**, **`export <pr>`** (renders the markdown document; never touches

SPEC.md:379

  • §5.4 specifies history behavior (store re-reads from disk on every save, ignores caller-supplied history, appends derived entries). None of this exists in the current saveArtifact path, which is a straightforward tmp+rename write (src/core/state.ts:18-25) with no pre-read/merge or derived history. The spec should either be rebased onto the implementation that adds this, or softened/flagged as a known divergence so it doesn’t mis-specify current behavior.
**Appended by the store, never by callers.** The save path itself derives and
appends history: it re-reads the file from disk on **every** save — even when
the caller just read it, because two writers share these files and appending
to the caller's copy would drop whatever the other recorded in between — and
**ignores any history the caller hands in**; disk is the only current copy.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadSPEC.md
Comment on lines +187 to +190
| `filed` | FiledInfo \| null | default `null`; never set on a sent artifact |
| `settledAt` | ISO-8601 string \| null | default `null`; when the row was settled — see below |
| `refresh` | RefreshInfo \| null | default `null` |
| `calibration` | Calibration \| null | default `null` |
Comment threadSPEC.md
Comment on lines +192 to +195
| `pendingChat` | PendingChat \| null | default `null` |
| `preChat` | ReviewSnapshot \| null | default `null` |
| `history` | HistoryEntry[] | OPTIONAL, **no default** — absent means the artifact predates history being kept, which surfaces MUST say rather than showing an empty log (§5.4) |

@jtomaszewski
jtomaszewski merged commit 8801bbe into mainAug 25, 2026
3 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.27.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jtomaszewski
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs: an RFC-style SPEC.md for the whole product - #44

Merged
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md
Aug 25, 2026
Merged

docs: an RFC-style SPEC.md for the whole product#44
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md

Conversation

@jtomaszewski

@jtomaszewskijtomaszewski commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Adds SPEC.md, a full service specification in the style of RFC-numbered specs: the artifact schema and every enum, the state store and history log, the seven-status lifecycle with its guards, the daemon's discovery/filing/reopen rules, the runner's tool policy and credential hygiene, the chat protocol, re-anchoring, the single GitHub write and auto-send, plus reference algorithms and a conformance checklist. It is written against the code and tests — which win on disagreement — and its Appendix B records the divergences found while writing it (stale CLI version string, README's re-review carryover claim, the CODE_REVIEW.md severity ladder, allowUserComments) rather than resolving them silently. The spec already describes the review history (#42) and the settled-row reopen rule (#43) as landed, so this should merge after those two. README's "How it works" and CLAUDE.md's Architecture section now point at it, with CLAUDE.md carrying the keep-it-true rule: a PR that changes specified behavior updates the spec in the same PR.

🤖 Generated with Claude Code


Open workspace in Conductor

The full service specification — schemas, lifecycle, tool policy, the
send path — precise enough to reimplement cerber from, written against
the code and tests (which win on disagreement; known divergences are
recorded in its Appendix B rather than silently resolved). It already
describes the review history (#42) and the settled-row reopen rule
(#43), so it should land after them. README and CLAUDE.md point at it,
CLAUDE.md with the keep-it-true rule that stops it rotting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an RFC-style SPEC.md intended to normatively describe Cerber’s behavior (artifact schema, lifecycle, daemon, runner/tool policy, API, CLI, and GitHub write boundary), and updates existing documentation to point readers at the spec as the engineering reference.

Changes:

  • Add SPEC.md as a full service specification for Cerber.
  • Link to SPEC.md from README.md in the lifecycle/docs area.
  • Update CLAUDE.md architecture guidance to require keeping the spec in sync with behavior changes.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
SPEC.mdAdds a comprehensive RFC-style specification covering data model, lifecycle, daemon, runner, API, CLI, and security invariants.
README.mdAdds a link and brief explanation positioning SPEC.md vs docs/lifecycle.md.
CLAUDE.mdAdds guidance that behavior changes described by the spec must update SPEC.md (or be recorded as divergences).
Suppressed comments (4)

SPEC.md:1268

  • The HTTP API table says PATCH /api/reviews/:key “stamps settledAt, clears filed”, but the current handler only updates status/verdictRecommendation and doesn’t set settledAt or clear filed (src/server/index.ts:351-379). Either update the route implementation or adjust the spec (and/or record this in Appendix B) so the API contract matches reality.
| `GET /api/reviews/:key` | one artifact | 404 |
| `PATCH /api/reviews/:key` | settle | only `reviewed`/`skipped` accepted (§8.1); stamps `settledAt`, clears `filed` |
| `POST/PATCH/DELETE …/comments[/:id]` | comment CRUD | delete is user-origin only in the UI |

SPEC.md:1607

  • Appendix A maps “§5 state store, history” to src/core/history.ts, but that file does not exist in the current repository. If history is meant to live elsewhere (or isn’t implemented yet), this mapping should be corrected so implementers can actually find the reference code.
| §4 domain model | `src/core/artifact.ts` |
| §5 state store, history | `src/core/state.ts`, `src/core/history.ts` |
| §6 configuration | `src/core/config.ts` |

SPEC.md:1383

  • The CLI section documents a cerber history <pr> command, but the current CLI does not define a history subcommand (see src/cli/index.ts, no .command("history")). If the command is planned but not yet shipped, it should be called out as a divergence / future work; otherwise update the CLI or remove this from the spec.
 and `running` artifacts.
- **`history <pr>`** — prints the review's history (§5.4): one line per
entry with local timestamp, actor, what happened, and the cause; says
plainly when a review predates the history being kept.
- **`list`**, **`export <pr>`** (renders the markdown document; never touches

SPEC.md:379

  • §5.4 specifies history behavior (store re-reads from disk on every save, ignores caller-supplied history, appends derived entries). None of this exists in the current saveArtifact path, which is a straightforward tmp+rename write (src/core/state.ts:18-25) with no pre-read/merge or derived history. The spec should either be rebased onto the implementation that adds this, or softened/flagged as a known divergence so it doesn’t mis-specify current behavior.
**Appended by the store, never by callers.** The save path itself derives and
appends history: it re-reads the file from disk on **every** save — even when
the caller just read it, because two writers share these files and appending
to the caller's copy would drop whatever the other recorded in between — and
**ignores any history the caller hands in**; disk is the only current copy.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadSPEC.md
Comment on lines +187 to +190
| `filed` | FiledInfo \| null | default `null`; never set on a sent artifact |
| `settledAt` | ISO-8601 string \| null | default `null`; when the row was settled — see below |
| `refresh` | RefreshInfo \| null | default `null` |
| `calibration` | Calibration \| null | default `null` |
Comment threadSPEC.md
Comment on lines +192 to +195
| `pendingChat` | PendingChat \| null | default `null` |
| `preChat` | ReviewSnapshot \| null | default `null` |
| `history` | HistoryEntry[] | OPTIONAL, **no default** — absent means the artifact predates history being kept, which surfaces MUST say rather than showing an empty log (§5.4) |

@jtomaszewski
jtomaszewski merged commit 8801bbe into mainAug 25, 2026
3 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.27.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jtomaszewski
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

docs: an RFC-style SPEC.md for the whole product - #44

Merged
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md
Aug 25, 2026
Merged

docs: an RFC-style SPEC.md for the whole product#44
jtomaszewski merged 1 commit into
mainfrom
jtomaszewski/write-spec-md

Conversation

@jtomaszewski

@jtomaszewskijtomaszewski commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Adds SPEC.md, a full service specification in the style of RFC-numbered specs: the artifact schema and every enum, the state store and history log, the seven-status lifecycle with its guards, the daemon's discovery/filing/reopen rules, the runner's tool policy and credential hygiene, the chat protocol, re-anchoring, the single GitHub write and auto-send, plus reference algorithms and a conformance checklist. It is written against the code and tests — which win on disagreement — and its Appendix B records the divergences found while writing it (stale CLI version string, README's re-review carryover claim, the CODE_REVIEW.md severity ladder, allowUserComments) rather than resolving them silently. The spec already describes the review history (#42) and the settled-row reopen rule (#43) as landed, so this should merge after those two. README's "How it works" and CLAUDE.md's Architecture section now point at it, with CLAUDE.md carrying the keep-it-true rule: a PR that changes specified behavior updates the spec in the same PR.

🤖 Generated with Claude Code


Open workspace in Conductor

The full service specification — schemas, lifecycle, tool policy, the
send path — precise enough to reimplement cerber from, written against
the code and tests (which win on disagreement; known divergences are
recorded in its Appendix B rather than silently resolved). It already
describes the review history (#42) and the settled-row reopen rule
(#43), so it should land after them. README and CLAUDE.md point at it,
CLAUDE.md with the keep-it-true rule that stops it rotting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an RFC-style SPEC.md intended to normatively describe Cerber’s behavior (artifact schema, lifecycle, daemon, runner/tool policy, API, CLI, and GitHub write boundary), and updates existing documentation to point readers at the spec as the engineering reference.

Changes:

  • Add SPEC.md as a full service specification for Cerber.
  • Link to SPEC.md from README.md in the lifecycle/docs area.
  • Update CLAUDE.md architecture guidance to require keeping the spec in sync with behavior changes.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
SPEC.mdAdds a comprehensive RFC-style specification covering data model, lifecycle, daemon, runner, API, CLI, and security invariants.
README.mdAdds a link and brief explanation positioning SPEC.md vs docs/lifecycle.md.
CLAUDE.mdAdds guidance that behavior changes described by the spec must update SPEC.md (or be recorded as divergences).
Suppressed comments (4)

SPEC.md:1268

  • The HTTP API table says PATCH /api/reviews/:key “stamps settledAt, clears filed”, but the current handler only updates status/verdictRecommendation and doesn’t set settledAt or clear filed (src/server/index.ts:351-379). Either update the route implementation or adjust the spec (and/or record this in Appendix B) so the API contract matches reality.
| `GET /api/reviews/:key` | one artifact | 404 |
| `PATCH /api/reviews/:key` | settle | only `reviewed`/`skipped` accepted (§8.1); stamps `settledAt`, clears `filed` |
| `POST/PATCH/DELETE …/comments[/:id]` | comment CRUD | delete is user-origin only in the UI |

SPEC.md:1607

  • Appendix A maps “§5 state store, history” to src/core/history.ts, but that file does not exist in the current repository. If history is meant to live elsewhere (or isn’t implemented yet), this mapping should be corrected so implementers can actually find the reference code.
| §4 domain model | `src/core/artifact.ts` |
| §5 state store, history | `src/core/state.ts`, `src/core/history.ts` |
| §6 configuration | `src/core/config.ts` |

SPEC.md:1383

  • The CLI section documents a cerber history <pr> command, but the current CLI does not define a history subcommand (see src/cli/index.ts, no .command("history")). If the command is planned but not yet shipped, it should be called out as a divergence / future work; otherwise update the CLI or remove this from the spec.
 and `running` artifacts.
- **`history <pr>`** — prints the review's history (§5.4): one line per
entry with local timestamp, actor, what happened, and the cause; says
plainly when a review predates the history being kept.
- **`list`**, **`export <pr>`** (renders the markdown document; never touches

SPEC.md:379

  • §5.4 specifies history behavior (store re-reads from disk on every save, ignores caller-supplied history, appends derived entries). None of this exists in the current saveArtifact path, which is a straightforward tmp+rename write (src/core/state.ts:18-25) with no pre-read/merge or derived history. The spec should either be rebased onto the implementation that adds this, or softened/flagged as a known divergence so it doesn’t mis-specify current behavior.
**Appended by the store, never by callers.** The save path itself derives and
appends history: it re-reads the file from disk on **every** save — even when
the caller just read it, because two writers share these files and appending
to the caller's copy would drop whatever the other recorded in between — and
**ignores any history the caller hands in**; disk is the only current copy.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadSPEC.md
Comment on lines +187 to +190
| `filed` | FiledInfo \| null | default `null`; never set on a sent artifact |
| `settledAt` | ISO-8601 string \| null | default `null`; when the row was settled — see below |
| `refresh` | RefreshInfo \| null | default `null` |
| `calibration` | Calibration \| null | default `null` |
Comment threadSPEC.md
Comment on lines +192 to +195
| `pendingChat` | PendingChat \| null | default `null` |
| `preChat` | ReviewSnapshot \| null | default `null` |
| `history` | HistoryEntry[] | OPTIONAL, **no default** — absent means the artifact predates history being kept, which surfaces MUST say rather than showing an empty log (§5.4) |

@jtomaszewski
jtomaszewski merged commit 8801bbe into mainAug 25, 2026
3 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.27.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jtomaszewski