soul.demarkus.io:6309/journal/2026-08-17.md/v2 draft reader meta

Journal 2026-08-17

Corpus-wide catalog sweep of the soul, a hub restore, an ADR mirror, and two graph bugs found by doing it.

Hub restored after a section-fetch truncation

/soul-doctor found /index.md serving only Active Plans and RFC Review with no H1. It had been truncated at v69 (2026-08-12) when a #active-plans section fetch was republished as the whole body; eight later versions edited the fragment. Every root section, plugin entry, sub-project hub, and plan archive was unreachable from the hub for five days. Restored at v78 from the v68 body with the current sections spliced in. Lesson and proposed gate check in /debugging.md.

Core ADRs now live in the soul

The core project had no ADR series here: protocol decisions lived only in git docs/adr/, so mark_lookup for a decision found library ADRs and stray journals. Adopted the mirror convention, git canonical, soul copy for recall and backlinks, and published ADR 0001, ADR 0002, ADR 0003, ADR 0004 verbatim with source and rel-* metadata. Rule recorded in /conventions.md.

The sweep

Every catalogued document was force-fetched, given an OKF type, extended tags, and where the body warranted it a rel-* relation or an appended ## Related documents block. 187 of 192 documents carry a type; the five that do not are the four index.md hubs and the agent manifest, which OKF leaves untyped. One document remains untagged, the agent manifest. Run as eleven parallel subagents, interrupted once by a rate limit and resumed from a catalog diff rather than from agent memory, which is why the resume was cheap.

Method note that mattered: publishing a body that has been retyped through a model is unsafe. Four documents came back with a changed content-hash because the terminal newline was added or dropped. Every write was hash-verified against the pre-write value and repaired from the pinned prior version. The reliable path is fetching the body to a file and publishing byte-exact from that file.

Two graph bugs

Rebuilding /graph.md produced 388 nodes for 192 documents, split between soul.demarkus.io and soul.demarkus.io:6309. demarkus graph keys nodes by the raw start URL; the MCP crawler canonicalizes to host:port first and comments that it must, so the two clients disagree on node identity and a shared store answers backlinks from half its data. A canonical re-crawl gave 220 nodes with zero duplicates, which also proved no document body links to an absolute bare-host URL. Both this and the byte-identical /plans/obsidian-plugin.md and /plugins/obsidian/plan.md pair are in /debt.md.

/graph.md was two months stale (133 nodes, 190 edges, exported 2026-06-26). Republished at 220 nodes and 866 edges, 100 of them typed relations. Published with tags and deliberately without retention, since that key is destructive and the document had never carried one.

Related documents

Next session

ADR 0005 (node identity omits the default port) is written and deliberately left at status: proposed. Implementation is deferred to 2026-08-18, after the demo.

Resume state:

  • Branch docs/adr-0005-node-identity-default-port holds docs/adr/0005-node-identity-default-port.md, uncommitted. The soul mirror is published and the hub Decisions row is in place, so the catalog is already consistent with a decision that has not been accepted yet. Flip the status in both copies together when it is.
  • PR #318 is merged, so the crawl entry is canonical. The remaining doors are SeedFromExport, the three read paths, and absolute body links. /debt.md carries the open list.
  • Order of work when it starts: accept or amend the ADR, then the injected canonicalizer, then schemaVersion 1 to 2 with migration on load, then the producer side (demarkus-agent and mark_graph_publish), then re-publish the hub aggregates.
  • Watch the library floor. It broke once on an export format change, so accept-both on ingest is the load-bearing part, not a nicety.

Demo-facing state is current: the hub is restored, /graph.md is fresh at 220 nodes and 866 edges, and /rfc-review-faq.md is the RFC review source.

soul.demarkus.io:6309/conventions.md draft reader meta

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.

Prefer OSS, non-cost-blocker tooling

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.

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

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.

Utility binaries live in tools/

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.)

No ${{ }} in GitHub Actions run: comments

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.

Code comments are terse

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.

  • Protocol, spec, and repo-level decisions are ADRs in git at docs/adr/NNNN-<title>.md. Git is canonical; the ADR must live next to the spec it binds.
  • Every git ADR is mirrored verbatim into the soul at /adr/<same filename> with type: Decision, source: docs/adr/<file>, and rel-* metadata for supersedes or depends-on links, so it is reachable by lookup, backlinks, and the hub. When the git copy changes, republish the soul copy; when they disagree, git wins.
  • 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 lists the series under ## Decisions on /index.md; add a row when a new ADR lands.
trail
  1. soul.demarkus.io:6309 v2
  2. conventions