Conventions and Working Agreements
Hard rules for how to work on demarkus with Fritz. These are collaboration and
repo/process conventions, distinct from the Go code-quality rules in
/guidelines.md and the idioms in /patterns.md.
Reference all three before writing code.
These were migrated from Claude Code's built-in auto-memory on 2026-06-06 when
that feature was disabled in favor of demarkus-soul as the single memory store.
They were reconstructed from index summaries; the original long-form rationale
for each was lost in the migration, so the "why" below is brief.
Collaboration
No sycophancy
On code or ideas. Critically review before presenting: layering violations,
missing edge cases, state desync, stale references, channel blocking, rune vs
byte vs cell-width confusion, silent error paths, leaky abstractions, wrong
architectural layer. Challenge ideas before agreeing: what's the downside? what
breaks? what's the simpler alternative? is this the right problem? Disagreement
backed by reasoning is expected.
No AI co-author trailer in commits
Never add Co-Authored-By: Claude ... or any AI co-author trailer to commits or
PRs. Fritz is the sole author.
Never ship anything broken
Grow PR scope rather than ship a known-broken surface. "A follow-up will fix it"
is not a valid mitigation. If a change leaves something broken, the fix belongs
in the same PR.
When recommending infra or platform tools, default to genuinely open-source
options. Flag BSL/SSPL/Elastic-licensed or paid-tier-gated tools explicitly and
offer OSS alternatives.
Question opt-in knobs that come from plans
When a plan calls for an Enabled bool or an "opt-in deployment," ask whether a
real "off" deployment actually exists. Default to baking the capability in
rather than adding a flag nobody will turn off.
Engineering value: robustness proven under failure
Adopted at Fritz's request on 2026-09-22. Use etcd's engineering discipline as
the primary quality reference for demarkus: explicit guarantees, fault
injection, recorded operation histories, and validation against a small model
of expected behavior. Reference: etcd robustness testing.
Correctness under crashes, cancellation, concurrency, and uncertain write
outcomes is a project value. A clean package graph and green happy-path tests
are useful evidence, but cannot establish those guarantees.
- State the invariants before changing storage, write reconciliation, authorization, cache invalidation, or service lifecycle behavior.
- Test failures at the boundaries where state changes: before and after commit, response loss, lock contention, cancellation while waiting, and removal or replacement of cached resources.
- Preserve acknowledged durable writes across recovery, immutable version history, authorization scope, and consistency between documents and derived indexes. Represent unknown or partial outcomes explicitly.
- Use deterministic scheduling and fault injection where possible. Collect operation histories and check them against the contract; use model-based or linearizability checks where the declared guarantee requires them. Race-detector success alone does not prove correct ordering.
- A regression test must fail on the defective behavior and survive later refactors. Test-framework changes must preserve their ability to expose known bugs.
- CI follows dependency direction: shared-module changes validate downstream consumers. Evaluate quality by demonstrated guarantees rather than file size, package count, or coverage percentage alone.
Apply this proportionately to demarkus's guarantees. This value does not require
Raft, etcd's deployment complexity, paid testing services, or blanket fault
suites for cosmetic changes. NATS Server is a secondary reference for bounded
network-service lifecycles; the Go standard library is the reference for
cohesive packages and precise APIs.
The initial required fixes are tracked in Refactor review debt. Future correctness work should strengthen these guarantees before adding abstraction for its own sake.
Architecture and layering
Core vs knowledge-system layering
The protocol core is permanent. Broker, universe, onboarding, gateway, MCP, and
the plugins are disposable overlays. Default to layering above the core; only
touch core if the feature survives throwing away every product built on top of
it.
No core changes for plugin work
Plugins must reuse the existing server/client/protocol surface. Discuss before
touching core for a plugin feature.
Repo conventions
demarkus supports macOS, Linux, and WSL. WSL follows Linux behavior. Native
Windows is not supported and must not receive Windows-specific implementation
or test work unless Fritz explicitly changes scope.
Branch for every change: never commit directly to main
Every change starts on a feature branch. Never commit to main, never push to
main directly. Land via PR so reviews and CI gates fire. This is true even for
work that looks small or obviously correct; the value of the rule is that it
is not negotiated per change. Push to main triggers auto-release (see
/patterns.md §CI/CD), so a direct commit to main also skips
the release sanity-check that a PR provides.
The first step of any code-touching task is git switch -c <branch> (or
confirm we are already on one). When in doubt, ask before staging changes.
This rule was added 2026-06-08 after a broker change landed on main as a
direct commit. See /journal/2026-06-08.md.
New sync, agent, or dev-ops binaries go in tools/, not client/cmd/.
Bump plugin pin versions on every update
plugins/claude-code/scripts/lib.sh SERVER / CLIENT / TOOLS_VERSION must move
with every plugin change.
No external runtime deps in the plugin
The claude-code plugin is pure awk/bash. No jq, no python, no node at runtime;
parse JSON in awk. (This governs the shipped hook/script runtime, not dev-only
test helpers.)
GH Actions parses run: blocks for expressions before shell semantics. A stray
${{ inside a # comment fails the entire workflow.
No em dashes in user-facing strings
CLI flag help, error messages, prompts, and MCP tool descriptions never use em
dashes. Use a semicolon, colon, or comma instead. Code comments follow the
surrounding file's idiom. Added 2026-07-06 after em dashes landed in the
agent's -publish-retention help text.
Added 2026-07-13 after a review pass found agent-written comments running to
10+ line essays.
A comment states only what the code cannot show: the why, an invariant, a
platform caveat, a rejected alternative that will tempt the next reader.
Target 1-3 lines. No narration of what the next line does, no restating the
function signature, no design-document prose in doc comments; deep rationale
belongs in the soul (debugging.md, plans) or the PR description, with the
comment carrying the one-line conclusion.
Refactor-on-touch: when editing code whose existing comments are verbose,
tighten them in the same edit. Scope this to the code being touched; no
repo-wide comment churn commits.
Where architectural decisions live
Added 2026-08-17 after /soul-doctor found the soul had no ADR series for the core project. Revised 2026-09-28 at Fritz's request: the soul is the home of the series, not a mirror.
- Protocol, spec, and repo-level decisions are ADRs in the soul at
/adr/NNNN-<title>.md with type: Decision, rel-* metadata for supersedes or depends-on links, and a status line (proposed or accepted, dated) at the top. The soul copy is canonical; nothing is written to docs/adr/ in git for a new decision.
docs/adr/ in git is a frozen archive of ADR 0001 to 0027 as they stood when the series moved. It is not updated; the soul copy wins where they differ, and ADR 0027 is accepted in the soul while the git copy still reads proposed.
- Code and commits reference a decision by its soul link (
mark://soul.demarkus.io/adr/<file> and the https://soul.demarkus.io/t/u/... web form), which is what the commit-message rule below already asks for.
- Sub-project decisions stay in the sub-project's own series (
/demarkus-library/adr/).
- Working notes about a decision (trail, rejected options, dated context) go in the plan or journal that produced it and link to the ADR. Do not record a decision only in a journal or in
/thoughts.md.
- The hub is /index/decisions.md; add a row when a new ADR lands and drop the
(proposed) marker when it is accepted.
Commit message bodies are links only
Added 2026-08-27 at Fritz's request. A commit message is a subject line plus a
body containing only the relevant soul links (the mark://soul.demarkus.io/...
URL and its https://soul.demarkus.io/t/u/... web form, typically the ADR or
plan behind the change). No prose body; the rationale lives in the linked
document, not the commit.
Added 2026-09-04 after the terse sweep. Everything under plugins/prompt-source/ and every MCP tool description (client/cmd/demarkus-mcp, tools/internal/broker/mcp_tools_list.go) is paid in tokens: session guidance per session, command and skill bodies per invocation, tool schemas per request in hosts that eager-load them (Cursor). Rules: terse prose (fragments, no filler, no rationale a step already implies; rationale lives in the soul), behavior intact (every step, rule, path, flag, shell fence, output shape, template directive), nothing volatile (no timestamps, ids, counts; they break prompt-cache prefixes), no em dashes, regenerate and bump the affected lineage in the same PR. CodeRabbit path instructions and plugins/prompt-source/README.md carry the same rule.
Roadmap is a hub plus topic files
Added 2026-09-04 after /roadmap.md reached 55KB. /roadmap.md holds one row per item (status, link) and nothing else; entries live in /roadmap/<topic>.md as ## <Name>: <STATUS> (<dates, PRs>) sections. Append the entry to its topic file and add the hub row in the same edit. New topic file when an area has none or a file passes about 16KB; never a second catch-all. Section headings are link anchors, so a shipped entry keeps its title and gains dated lines. Full rule at /roadmap.md#format; the plugin's remember skill carries the same layout for every project.
Hubs are link pages
Added 2026-09-04 after asking whether per-section hubs help or hinder the graph. They help when a hub is only links: backlinks land on the child and its section, the catalog ranks small focused documents, and mark_explore on the hub orients in one call. They hinder when a hub restates its children (status columns, summaries), because that second copy drifts, and when fan-out grows without bound, because every child becomes one hop from every other and relatedness signals wash out.
Rules for every hub (index.md, roadmap.md, any link page):
- Links plus one line each. No content, status, dates, or summaries copied from children; the child is the single source.
- Each child links back to its hub.
- About 40 outbound documents, then a second-level hub. Anchored links into one document count once.
- Real relations go in
rel-* metadata, not hub adjacency.
- Prefer generated hubs where the agent can build them, as with
/graph.md and the hash indexes.
Revision to the roadmap rule above, same day: entry headings are the name alone and never change; Status: <active|planned|done|backlog> (<dates, PRs>) is the first line under the heading and is the only place status lives. The hub lists topic files and entries by name. The remember skill carries the same rules.
Promoted to mark://root/.well-known/demarkus/style.md@v1 via knowledge on 2026-09-04 (section only; the rest of this document stays personal). The shared copy is authoritative for hub and status-document structure.
Scope note, same day: the roadmap hub-plus-topic-files format above is this project's own practice. The shared rule, in the remember skill, the knowledge system's style guide and template, and the memory broker seed, is the generic hub rule only (plus "a document that outgrows one fetch splits into a hub plus topic files"); other projects lay out their roadmap as they see fit.
Edit a prompt procedure whole, never sentence by sentence
Added 2026-09-08 after PR #431, where six review rounds on one paragraph of the promote skill each fixed one sentence, and one of those fixes contradicted a rule three sentences away (incomplete-dedup named as a gate input while the same step said it stops the cascade).
A skill or command template is a procedure without a compiler; nothing checks that a rule added in one sentence agrees with the rest. Rules for any change under plugins/prompt-source/:
- Read the whole step, and any step it hands off to, before changing it. A finding on one sentence is fixed by rewriting the step.
- Every named state or outcome (
incomplete-dedup, catalog-only, not-permitted) is defined once, at its first use, as terminal or carried forward; every later mention follows that definition. Grep the template for the name before adding a use.
- Every call the step makes has a failure line in the same step; an added call brings its failure handling with it.
- After the edit, read the step once more against the cascade rule at the top of the skill. Then regenerate and run pre-commit.
- Review rounds that keep landing on the same paragraph mean the paragraph was patched, not rewritten. Stop and rewrite it.
Suggested commit messages are five words
Asked 2026-10-01: when Fritz asks for a commit message, give a conventional-commit type and scope followed by exactly five words, for example feat(knowledge): derive federation graph from changes. No body, no co-author.
One branch per piece of work, not per fix
When a feature branch is already checked out, follow-up fixes, review findings and small related changes go on that branch. Never open a new branch per fix or per finding unless the user asks for one: a pile of branches is friction, and every switch risks stranding uncommitted work. This narrows branch for every change, which is about never committing to main. Added 2026-10-14 after a suggested fix/style-size-warning branch.