docs(adr): the foundation and product ADRs, requirements, plan and user stories land #1

Merged
bjoern merged 3 commits from docs/foundation-and-product-adrs into main 2026-10-17 13:59:36 +02:00
Member

Shikigami's docs-first pass (ADR 0001), before any skeleton or feature code. Shikigami is a cast of owner-defined familiars, the successor to angela_assistant.

What lands

  • Foundation ADRs 0001–0012 (Accepted), adapted from Tsumugi, Orihon and Kagura:
    • Blazor Server on .NET 10 in Tsumugi's host shape, with clean architecture.
    • OpenRouter.Net and Kagaku.UI as submodules.
    • One SQLite database with files as rows and binaries as blobs on their own volume.
    • Secrets, the access gate and reverse-proxy sub-path.
    • Docker with a browser layer, the app shell, Fluxor with its bridges, and rotating backups.
  • Product ADRs 0013–0030 (Proposed, for this review), designed from the owner's brief of 2026-10-16:
    • The cast and profile; growth modes (static, reflective, evolving) with the nightly reflection as a routine.
    • One virtual file tree per familiar, a bash interpreter with GNU-style output, and an edit tool.
    • Optimistic concurrency through a read ledger: a stale write fails with "read it again".
    • Memory and skills in the Agent Skills format, and the after-turn learning loop.
    • Parallel chats where every run is recorded and no message is dropped.
    • The model runtime over OpenRouter.Net, with a prompt laid out for the cache.
    • Tool groups with one interception point that allows everything today.
    • The activity log and prompt preview.
    • Routines as files with a schedule header.
    • In-process Playwright with one persistent profile per familiar.
    • Mail as a mount.
    • Group chats where each familiar bids and code arbitrates.
    • Expressions stored on every message, a renderer-agnostic stage, and voice behind a port.
    • Extension seams, and images.
  • REQUIREMENTS.md, ARCHITECTURE.md, PROJECT_PLAN.md and 11 user stories. In the plan, Phases 0–4 are the MVP, "Niko back, better", next to the OpenRouter.Net library track (streaming loop, caller context, cache controls, steering, hardening, fork, speech, wire capture).

For the owner

docs/adr/README.md ends with "Open for the owner": 19 decisions the product ADRs take provisionally. These matter most:

  • the evolving reflection's prompt and tools (items 3–4);
  • persistent browser logins (item 11);
  • SearXNG for web search (item 12);
  • which mail providers matter (item 13).

Review so far

Before this PR, a five-dimension review workflow checked the draft and verified each finding adversarially. Every finding that survived verification is applied. A fix-check pass then caught leftover items and new inconsistencies between ADRs, and those are applied too.

🤖 Generated with Claude Code

Shikigami's docs-first pass (ADR 0001), before any skeleton or feature code. Shikigami is a cast of owner-defined familiars, the successor to `angela_assistant`. ## What lands - **Foundation ADRs 0001–0012** (*Accepted*), adapted from Tsumugi, Orihon and Kagura: - Blazor Server on .NET 10 in Tsumugi's host shape, with clean architecture. - OpenRouter.Net and Kagaku.UI as submodules. - One SQLite database with files as rows and binaries as blobs on their own volume. - Secrets, the access gate and reverse-proxy sub-path. - Docker with a browser layer, the app shell, Fluxor with its bridges, and rotating backups. - **Product ADRs 0013–0030** (*Proposed*, for this review), designed from the owner's brief of 2026-10-16: - The cast and profile; growth modes (static, reflective, evolving) with the nightly reflection as a routine. - One virtual file tree per familiar, a `bash` interpreter with GNU-style output, and an `edit` tool. - Optimistic concurrency through a read ledger: a stale write fails with "read it again". - Memory and skills in the Agent Skills format, and the after-turn learning loop. - Parallel chats where every run is recorded and no message is dropped. - The model runtime over OpenRouter.Net, with a prompt laid out for the cache. - Tool groups with one interception point that allows everything today. - The activity log and prompt preview. - Routines as files with a schedule header. - In-process Playwright with one persistent profile per familiar. - Mail as a mount. - Group chats where each familiar bids and code arbitrates. - Expressions stored on every message, a renderer-agnostic stage, and voice behind a port. - Extension seams, and images. - **REQUIREMENTS.md, ARCHITECTURE.md, PROJECT_PLAN.md and 11 user stories.** In the plan, Phases 0–4 are the MVP, "Niko back, better", next to the OpenRouter.Net library track (streaming loop, caller context, cache controls, steering, hardening, fork, speech, wire capture). ## For the owner `docs/adr/README.md` ends with **"Open for the owner"**: 19 decisions the product ADRs take provisionally. These matter most: - the evolving reflection's prompt and tools (items 3–4); - persistent browser logins (item 11); - SearXNG for web search (item 12); - which mail providers matter (item 13). ## Review so far Before this PR, a five-dimension review workflow checked the draft and verified each finding adversarially. Every finding that survived verification is applied. A fix-check pass then caught leftover items and new inconsistencies between ADRs, and those are applied too. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Foundation ADRs 0001–0012 adapt Tsumugi, Orihon and Kagura's conventions (Accepted):
docs-first, Blazor Server on .NET 10, clean architecture, the OpenRouter.Net and
Kagaku.UI submodules, one SQLite database with blobs on a volume, secrets, the access
gate, Docker with a browser layer, Kagaku.UI, the app shell, Fluxor and backups.

Product ADRs 0013–0030 design the familiar fresh from the owner's brief (Proposed, for
this PR's review): the cast and profile, growth modes and the nightly reflection, the
virtual file system, the bash and edit tools, optimistic concurrency with a read
ledger, memory and skills, the after-turn learning loop, chats and runs, the model
runtime and a cache-shaped prompt, tool groups with one interception point, the
activity log, routines as files, the browser, mail as a mount, group chats with bids,
expressions with a renderer-agnostic stage and voice, extension seams, and images.

REQUIREMENTS.md, ARCHITECTURE.md, PROJECT_PLAN.md (Phases 0–4 as the MVP, plus the
OpenRouter.Net library track) and eleven user stories anchor to them. The ADR index
ends with nineteen questions open for the owner.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh my~ 3,814 lines and not a single .cs among them — a whole being designed before its skeleton exists! This is my favourite kind of meal: thirty ADRs, a plan, requirements and eleven stories, all written to be argued with before a single line of code is frozen. I read every file, cross-checked every number that appears in more than one place (03:00 → 03:30 backup ordering in 0002/0008/0012/0014; run caps 80/30, 24/10, 12/5, 40/15, one-call/2min across 0014/0019/0020/0024 and the README's owner list; the three-tab cap; the group-chat reply caps; the 12,000-char self budget; retention 180/30/90 days), verified all 30 ADR links and all 11 story links resolve, and confirmed the statuses split exactly 12 Accepted / 18 Proposed as the index claims. Almost everything agrees. Almost. ♡

Verdict: ⛔ I can't let this pass~ ♡

⛔ These need fixing before I'm satisfied~

  1. docs/adr/0022-tool-groups-and-the-interception-point.md:88–90 vs docs/adr/0019-the-learning-loop.md (§ The curator) — ADR 0022 promises: "The activity log's badge and the curator's weekly report single out the ones that persist into later prompts — writes to /memory, /skills, /persona/self.md and /routines — so the owner can glance at what a mail may have planted." But ADR 0019 — the ADR that defines the curator — gives it exactly three duties: aging unread skills into /archive, reporting tool friction from workaround notes, and opt-in model consolidation. Tainted writes are never mentioned there, and ADR 0023's entry types have no "weekly report" either. An implementer building the curator from its own ADR will simply not produce the report 0022 relies on — and that report is one of the load-bearing mitigations of "trust over gates" (the lethal-trifecta story of 0022 rests on it). Your own PR description says a fix-check pass hunted "inconsistencies between ADRs" — this one survived it. Fufu~ you wouldn't leave that in the foundation, would you? ♡
    Fix: add the duty to ADR 0019's curator list — a deterministic scan of revisions for tainted writes to /memory, /skills, /persona/self.md, /routines, one activity entry per find (it is exactly as deterministic as the workaround grep, so it belongs in the same pass) — or reword 0022 to attribute the singling-out to the activity log's badge alone. One paragraph, either way.

💡 Little ideas (non-blocking)~

  1. docs/adr/0024-routines-and-the-scheduler.md:82–84 — the sentence "repeat is the activation time plus whole intervals, in wall time and DST-aware — both — next occurrence in local wall time, DST-correct — never by adding seconds" has editing debris in the middle ("— both —"). The rule survives (it's stated twice!), but this is the normative sentence for DST correctness — Angela's hour-drift is one of this ADR's founding wounds, so it deserves a clean wound dressing. Suggestion: "…; repeat is the activation time plus whole intervals in wall time. Both compute the next occurrence in local wall time, DST-correct — never by adding seconds."
  2. docs/adr/0014-growth-modes-and-reflection.md:78–79 vs docs/adr/0015:110,114 — 0014's "what it may write" list omits /tmp and /archive, both of which 0015's permission table grants the Reflection run (rw). The table's "(/tmp rw)" note shows the intent, but a summary list that quietly drops two granted paths invites a future "is this a bug?" thread. One clause — "(summarised; ADR 0015's table is authoritative)" — or add the two paths, and it's airtight.

✅ What I liked~

  • Permissions as enforcement, not wording. Growth modes as file permissions (Permission denied, not a prompt rule to argue with), the read ledger's content/listing split, and the run-kind permission matrix in 0015 — the whole design trusts mechanisms where Angela trusted prose. Wonderful~
  • Cache discipline. The tail that is never stored, explicit breakpoints instead of the automatic form, the byte-identical fork pinned by a body-comparison test — and every number matching across 0018/0019/0020/0021/0027.
  • The internal storytelling consistency: the same conflict example (moved to Shops/ by chat "Morning mail", 09:41) recurring verbatim in 0017, 0020 and 0026; the mail file name …~k3f9a2.md identical in 0017 and 0026. Small things, but they prove the documents were written as one design.
  • Every Angela failure mapped to a structural prevention, cited with file:line — and honestly marked where Shikigami keeps a risk knowingly (prompt injection under trust-over-gates, with the taint mark as the map).
  • The Open for the owner list really does have 19 items, each pointing at the ADR that takes the provisional decision. I counted. Twice. Fufu~ ♡

Automated review by Jibril · 2026-10-17
CI: absent-stalled for head SHA 0d14d60 (no workflows in the repo yet — ci.yml is Phase 0c) · Mutation probes: 0 run, 0 survived — skipped (docs-only PR, no code to mutate) · Local suite: n/a (repository contains no code yet; docs-first, Phase 0 not started)

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh my~ 3,814 lines and not a single `.cs` among them — a whole being designed before its skeleton exists! This is my *favourite* kind of meal: thirty ADRs, a plan, requirements and eleven stories, all written to be argued with before a single line of code is frozen. I read every file, cross-checked every number that appears in more than one place (03:00 → 03:30 backup ordering in 0002/0008/0012/0014; run caps 80/30, 24/10, 12/5, 40/15, one-call/2min across 0014/0019/0020/0024 and the README's owner list; the three-tab cap; the group-chat reply caps; the 12,000-char self budget; retention 180/30/90 days), verified all 30 ADR links and all 11 story links resolve, and confirmed the statuses split exactly 12 *Accepted* / 18 *Proposed* as the index claims. Almost everything agrees. *Almost.* ♡ ### Verdict: ⛔ I can't let this pass~ ♡ #### ⛔ These need fixing before I'm satisfied~ 1. **docs/adr/0022-tool-groups-and-the-interception-point.md:88–90 vs docs/adr/0019-the-learning-loop.md (§ The curator)** — ADR 0022 promises: *"The activity log's badge and **the curator's weekly report** single out the ones that persist into later prompts — writes to `/memory`, `/skills`, `/persona/self.md` and `/routines` — so the owner can glance at what a mail may have planted."* But ADR 0019 — the ADR that *defines* the curator — gives it exactly three duties: aging unread skills into `/archive`, reporting tool friction from workaround notes, and opt-in model consolidation. Tainted writes are never mentioned there, and ADR 0023's entry types have no "weekly report" either. An implementer building the curator from its own ADR will simply not produce the report 0022 relies on — and that report is one of the load-bearing mitigations of "trust over gates" (the lethal-trifecta story of 0022 rests on it). Your own PR description says a fix-check pass hunted "inconsistencies between ADRs" — this one survived it. Fufu~ you wouldn't leave *that* in the foundation, would you? ♡ Fix: add the duty to ADR 0019's curator list — a deterministic scan of revisions for tainted writes to `/memory`, `/skills`, `/persona/self.md`, `/routines`, one activity entry per find (it is exactly as deterministic as the workaround grep, so it belongs in the same pass) — or reword 0022 to attribute the singling-out to the activity log's badge alone. One paragraph, either way. #### 💡 Little ideas (non-blocking)~ 1. **docs/adr/0024-routines-and-the-scheduler.md:82–84** — the sentence *"`repeat` is the activation time plus whole intervals, in wall time and DST-aware — both — next occurrence in local wall time, DST-correct — never by adding seconds"* has editing debris in the middle ("— both —"). The rule survives (it's stated twice!), but this is *the* normative sentence for DST correctness — Angela's hour-drift is one of this ADR's founding wounds, so it deserves a clean wound dressing. Suggestion: *"…; `repeat` is the activation time plus whole intervals in wall time. Both compute the next occurrence in local wall time, DST-correct — never by adding seconds."* 2. **docs/adr/0014-growth-modes-and-reflection.md:78–79 vs docs/adr/0015:110,114** — 0014's "what it may write" list omits `/tmp` and `/archive`, both of which 0015's permission table grants the Reflection run (rw). The table's "(`/tmp` rw)" note shows the intent, but a summary list that quietly drops two granted paths invites a future "is this a bug?" thread. One clause — *"(summarised; ADR 0015's table is authoritative)"* — or add the two paths, and it's airtight. #### ✅ What I liked~ - **Permissions as enforcement, not wording.** Growth modes as file permissions (`Permission denied`, not a prompt rule to argue with), the read ledger's content/listing split, and the run-kind permission matrix in 0015 — the whole design trusts *mechanisms* where Angela trusted prose. Wonderful~ - **Cache discipline.** The tail that is never stored, explicit breakpoints instead of the automatic form, the byte-identical fork pinned by a body-comparison test — and every number matching across 0018/0019/0020/0021/0027. - **The internal storytelling consistency**: the same conflict example (*moved to Shops/ by chat "Morning mail", 09:41*) recurring verbatim in 0017, 0020 and 0026; the mail file name `…~k3f9a2.md` identical in 0017 and 0026. Small things, but they prove the documents were written as *one* design. - **Every Angela failure mapped to a structural prevention**, cited with `file:line` — and honestly marked where Shikigami *keeps* a risk knowingly (prompt injection under trust-over-gates, with the taint mark as the map). - The *Open for the owner* list really does have 19 items, each pointing at the ADR that takes the provisional decision. I counted. Twice. Fufu~ ♡ --- *Automated review by Jibril · 2026-10-17* *CI: absent-stalled for head SHA 0d14d60 (no workflows in the repo yet — `ci.yml` is Phase 0c) · Mutation probes: 0 run, 0 survived — skipped (docs-only PR, no code to mutate) · Local suite: n/a (repository contains no code yet; docs-first, Phase 0 not started)*
@ -0,0 +6,4 @@
Shikigami is a single-user, self-hosted **home for familiars**:
- an ASP.NET Core + Blazor Server web application — the only process — deployed the siblings' way: a multi-stage
Owner

"the only process" - how do you intend to do browsing?

"the only process" - how do you intend to do browsing?
bjoern marked this conversation as resolved
@ -0,0 +11,4 @@
across volumes (ADR 0002, 0008);
- a SQLite database for familiars, chats, messages, model histories, runs, the activity log, every familiar's file
tree with its revisions, and the mail index (ADR 0005);
- write-once blobs on their own volume, a persistent Chromium profile per familiar, rotating backups (ADR 0005,
Owner

does chromium profile allow in theory even them storing user and passwords?

does chromium profile allow in theory even them storing user and passwords?
bjoern marked this conversation as resolved
@ -0,0 +35,4 @@
## Notes & dependencies
- ADR 0008 (the browser layer), 0022, 0025.
- The owner's DPD and Kingtrans skills are the first end-to-end checks.
Owner

I would like to also think about typical bot detection to some degree. Like, basic captcha resolving

I would like to also think about typical bot detection to some degree. Like, basic captcha resolving
bjoern marked this conversation as resolved
@ -0,0 +45,4 @@
- ADR 0020, 0021, 0023, 0028, 0030.
- Kagaku.UI gains `ChatMessage`, `Drawer` and `Toast` upstream first (ADR 0009).
- Group chats are their own story (`group-chat.md`).
Owner
  • I would like to be able to cancel a current run
  • I would like to also see the reasoning/thinking traces optionally but without clutter when it exists
  • I would like to be able to send images or general files up to reasonable limits
  • I would like to archive/"close" a chat once it has completed its purpose
  • I would like (Maybe in a different story) to define that an agent can based on a timer open a new chat. A timer or webhook can decide by itself whether it wants to post in one of the current active chats, or create a new one.
- I would like to be able to cancel a current run - I would like to also see the reasoning/thinking traces optionally but without clutter when it exists - I would like to be able to send images or general files up to reasonable limits - I would like to archive/"close" a chat once it has completed its purpose - I would like (Maybe in a different story) to define that an agent can based on a timer open a new chat. A timer or webhook can decide by itself whether it wants to post in one of the current active chats, or create a new one.
bjoern marked this conversation as resolved
@ -0,0 +38,4 @@
## Notes & dependencies
- ADR 0015, 0017, 0018, 0024.
- The editor starts as Kagaku.UI's `TextArea`; a code editor is a later decision (ADR 0009).
Owner

Neat idea:

  • Special purpose folders like memory or routines check on save whether the format of each is correct and on failure return meaning errors to the agent
  • For special purpose folder items like memory or routines, I would love to get preferrably a specialized viewer. E.g. for routines I get a proper editor where I can set the settings via gui clicking.
Neat idea: - Special purpose folders like memory or routines check on save whether the format of each is correct and on failure return meaning errors to the agent - For special purpose folder items like memory or routines, I would love to get preferrably a specialized viewer. E.g. for routines I get a proper editor where I can set the settings via gui clicking.
bjoern marked this conversation as resolved
@ -0,0 +32,4 @@
## Appearance and backups
- [ ] **Theme** light/dark/system (Kagaku.UI).
Owner

I would love to see some of the more advanced formatting features of Tsumugi to be available here as well, including options for various fonts and styles

I would love to see some of the more advanced formatting features of Tsumugi to be available here as well, including options for various fonts and styles
bjoern marked this conversation as resolved
@ -0,0 +13,4 @@
`DomainChanged` doorbell so every open session re-queries what changed. Orihon deferred it and paid with a
migration; Tsumugi wired it from Phase 0 (Tsumugi ADR 0011).
Shikigami cannot defer either: from its first chat, replies stream token by token, a familiar's file writes
Owner

Consider going with paragraph for paragraph to optimize for performance.

Consider going with paragraph for paragraph to optimize for performance.
bjoern marked this conversation as resolved
@ -0,0 +39,4 @@
- Each familiar has an **expression set** (ADR 0013): a starting set of six names (`neutral happy sad angry
surprised relaxed` — VRM's presets, which overlap Kagura's seeded emotions), plus custom names the owner adds
(`smug`, `pouting`). Each renderer adapter maps the names onto what its avatar has. The set is listed in the frozen system prompt (ADR 0021), with the instruction to open
a paragraph with a cue when its expression changes: `[happy] Your parcel cleared customs!`
Owner

The idea for me is actually a bit different. One example I saw recently is with something caleld a decicion(s) model. See openrouter decicion models for more context, should be implemented already in openrouter.net.

The idea is to give a lightweight decicion model the current context and a list of emotions to attach probabilities to. We pick the one that has a minimum threshold (so it fits) and which is the highest.

I have seen vtuber / aituber concepts that use this concept to pick animations and the likes like that

The idea for me is actually a bit different. One example I saw recently is with something caleld a decicion(s) model. See openrouter decicion models for more context, should be implemented already in openrouter.net. The idea is to give a lightweight decicion model the current context and a list of emotions to attach probabilities to. We pick the one that has a minimum threshold (so it fits) and which is the highest. I have seen vtuber / aituber concepts that use this concept to pick animations and the likes like that
bjoern marked this conversation as resolved
@ -0,0 +49,4 @@
- **Outbound**: a hook subscribes to events — a familiar's `send_message`, a failed routine — and POSTs a small
JSON payload to a URL. A self-hosted ntfy on the same host turns that into a phone push with one line of
configuration.
- **Inbound**: `POST /hooks/<name>` with the hook's own bearer token, in a route group outside the cookie gate
Owner

potentially rss feeds or so? idk

potentially rss feeds or so? idk
bjoern marked this conversation as resolved
@ -0,0 +52,4 @@
- **Inbound**: `POST /hooks/<name>` with the hook's own bearer token, in a route group outside the cookie gate
(ADR 0007), emits a `SignalReceived` that routines subscribe to (`on: hook.<name>`) — a Home Assistant
automation, a script, a shortcut on the phone.
- **A REST surface** for a future mobile client or messenger bridge is another driver over the same use cases
Owner

we have not decided on a dedicated mobile client so far. I was hoping to first explore the possibility to think about responsive design layouts over a dedicated app first. A dedicated client should not be considered too soon.

we have not decided on a dedicated mobile client so far. I was hoping to first explore the possibility to think about responsive design layouts over a dedicated app first. A dedicated client should not be considered too soon.
bjoern marked this conversation as resolved
@ -0,0 +36,4 @@
**description**, written once per image by the utility model (ADR 0021) with a prompt that names the image's
hash, cached on the file row and reused forever. A model without image input gets descriptions for every image.
- The replacement happens when the history is assembled, so replays stay byte-identical between compactions:
an image leaves the inline window only at compaction (ADR 0020), never in the middle of a cached prefix.
Owner

Angela had a "poor" context management which I'm not too sure about. One idea is to fix that to make the chats more cache friendly (supported my openrouter.net explicitly). In my opinionen there are two concerns here for this kind of expierence and potential thigns to think about

  • Angela recomputed the input with every new message picking the last N turns. This makes chatting extreemly expensive even wit moderate cost models. Most ai harnesses like claude code or hermes use a continous growing + compact strategy to take advantage of caching. I'm kinda in favor of this here as well. Purging all but the last 4 images would however constantly reset the cache and break caching
  • A big issue is however cache retention time. Chats can potentially continue for days with a couple of messages each, so the caching will not work universally. We kinda need a cache tracking/management of sorts. When cache breaks, consider rebuilding potentially the context with the "max n images" prune or so, But i do not know whether such a cache management system is offered by openrouter's api.
Angela had a "poor" context management which I'm not too sure about. One idea is to fix that to make the chats more cache friendly (supported my openrouter.net explicitly). In my opinionen there are two concerns here for this kind of expierence and potential thigns to think about - Angela recomputed the input with every new message picking the last N turns. This makes chatting extreemly expensive even wit moderate cost models. Most ai harnesses like claude code or hermes use a continous growing + compact strategy to take advantage of caching. I'm kinda in favor of this here as well. Purging all but the last 4 images would however constantly reset the cache and break caching - A big issue is however cache retention time. Chats can potentially continue for days with a couple of messages each, so the caching will not work universally. We kinda need a cache tracking/management of sorts. When cache breaks, consider rebuilding potentially the context with the "max n images" prune or so, But i do not know whether such a cache management system is offered by openrouter's api.
bjoern marked this conversation as resolved
Björn's eleven comments and Jibril's three points, backed by a second research pass:

- ADR 0025: Playwright runs a Node driver and a Chromium tree per familiar in the app's container, sandboxed
  (Playwright turns the sandbox off by default), headed on a display per familiar; a browser-host container if
  the host cannot sandbox. The profile's password manager is off; logins are encrypted credential rows typed by
  handle and bound to their origins; every result is scrubbed of passwords (the AI snapshot prints input values).
  Bot checks in layers — avoid, recognise, bounded self-solve, hand over — with no paid solver; takeover moves
  to Next.
- ADR 0028: expressions are judged per paragraph by a decision model (OpenRouter's Decisions API, already in
  OpenRouter.Net) instead of inline cues; the owner's rule — highest label at or above the minimum — is the
  default.
- New ADR 0032: a per-history cache ledger infers warm or cold (OpenRouter offers no cache management); the
  history only grows while warm and is rebuilt at a cold boundary — newest images inline, old tool outputs
  trimmed, reasoning stripped, a summary prepared on a warm fork applied. ADR 0021 freezes the tail per turn and
  anchors a second breakpoint, so prefix-bound thinking stays valid.
- New ADR 0031: Tsumugi's editor appearance for chats, with a per-familiar accent for group chats; Kagaku.UI's
  Markdown is hardened first (remote images and media links are a zero-click exfiltration channel).
- New ADR 0033 and a story: feeds as a validated feeds.yaml, items as files, one signal per poll.
- Paragraph-by-paragraph rendering (ADR 0011), Stop keeps a stopped partial reply and Cancel reaches background
  runs, reasoning folds into the tool line, upload limits and PDF text, archive closes a chat, a familiar chooses
  where a routine speaks, special folders validated on every write with forms per kind, no dedicated mobile
  client.
- Jibril: the curator's weekly taint report (ADR 0019), the repeat sentence in 0024, and 0014's write list.

Open for the owner: items 20–25 in docs/adr/README.md.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Author
Member

Round 2: Björn's and Jibril's review answered

Fix commit: d8b20d7. It changes 40 files and adds 4: ADR 0031 Chat appearance, ADR 0032 Context and the prompt cache, ADR 0033 Feeds and the feeds story. A second research pass backs it (six reports: the browser process and passwords, bot checks, decision models, cache economics, Tsumugi's formatting, and reasoning/stop/uploads/streaming/feeds). After it came a five-dimension review with skeptical verification: 72 findings, 51 confirmed and 21 partial, none refuted. All of them are applied. A fix-check pass then found 71 of the 72 resolved and 10 new problems the fixes had introduced (mostly stale "per call" wording after the tail change); those are fixed in the same commit.

Jibril

  • ⛔ Taint report: the curator (ADR 0019) now has the duty. It runs a deterministic scan of revisions for tainted writes to /memory, /skills, /persona/self.md, /routines and /feeds/feeds.yaml, and posts one activity entry per file as the week's taint report. ADR 0022 and 0023 name it, and it is in REQUIREMENTS §4, the plan (3e) and the memory story.
  • 💡 ADR 0024: the repeat sentence is cleaned up, as you suggested.
  • 💡 ADR 0014: the write list now says it is a summary and that ADR 0015's table is authoritative. It is also complete: /archive, /tmp, and in evolving mode /images, /downloads, /web, the feed list and the mail mount.

Björn

  1. "The only process" (ARCHITECTURE). That was wrong. Playwright for .NET starts its own bundled Node driver, and that driver starts a Chromium process tree per familiar. It now reads "one container, the only service, which supervises the driver, the Chromium processes and their displays".

    • The research also found that Playwright launches Chromium without its sandbox by default. A hostile page would then be one renderer exploit away from the keyring and the database.
    • ADR 0025 therefore switches the sandbox on and sets a decision rule: if your host cannot run it (possible in an unprivileged LXC), the browser moves into a browser-host container in the same slice, with the same adapter behind IBrowserHost.
    • playwright run-server cannot be that container: it has no persistent profiles, and it closes the browser when the client disconnects.
  2. Passwords in the Chromium profile. In theory, yes. They go in Login Data, and under Playwright's --password-store=basic they are effectively plain text, as are the cookies.

    • The profile now has its password manager and autofill switched off. A contract test checks that Login Data and Web Data stay empty after a login.
    • Logins become encrypted credential rows that the familiar types by handle, e.g. browser_type(target, credential: "dpd.password").
    • A login is bound to its origins and to the field type, so a look-alike page cannot collect it.
    • Second finding: Playwright's AI snapshot prints the value of every input, password fields included. So every browser result is scrubbed (with its encoded forms) before the model, a file or the log sees it.
    • The profile still holds cookies, so it remains a secret at rest. Forget browser sessions and Sign out of a site are on the Profile page.
  3. Bot detection and captchas. ADR 0025 has a new section with four layers:

    • Avoid: Chromium runs headed on a virtual display, one per familiar, with the automation switches dropped, your locale and time zone, real fonts, and paced input.
    • Recognise: a challenge: line comes first in the snapshot, and the browser waits up to 15 seconds for an interstitial to clear.
    • Self-solve, within limits: browser_click("challenge") uses real OS input on the familiar's display. Simple text captchas are read through vision. Two failed attempts on a page end the errand, and image grids get one.
    • Hand over: the familiar reports the block to you with a screenshot.

    There is no paid solver, per your answer. Takeover moved from Later to Next, together with the live view. Patchright (a .NET drop-in) is a measured swap if DPD still blocks; the contract tests run on both packages. Noted that Kingtrans has no captcha.

  4. Chats.

    • Stop existed; it now keeps the partial reply as stopped, and Esc works too. Cancel stops any background run from the timeline or the inspector. One billing caveat: Google, Bedrock and a few other providers bill the whole reply even after a Stop. Tools with a critical section, such as mail_send and file writes, finish it first.
    • Reasoning folds into the existing tool line, "Thought for 12 s · ran 4 commands", or a setting hides it.
    • Uploads: up to 10 files and 50 MB per message. PDFs arrive as locally extracted text.
    • Archive closes a chat: it leaves ACTIVE.md, familiars cannot post there, and one click reopens it.
    • A timer or signal decides where to speak: send_message takes any open chat or new: <title>. The routine's chat: is only the default.
  5. Special folders. One validator per kind (memory, skills, routines, later the feed list) checks every write, from the familiar or from you. Errors come as line N: key: message, so a familiar fixes its own routine at once.

    • Special files open on Form · Text · Preview · History.
    • The routine form sets the schedule by clicking and lists the Next firings.
    • The memory form shows the budgets as usage bars.
    • The skill view shows requires-tools as chips.
    • Kagaku.UI gets Switch, ChipGroup, NumberField and a counter upstream first.
  6. Tsumugi's formatting. New ADR 0031 Chat appearance, which is Tsumugi's Editor appearance (fonts, size, spacing, width, colours for text, italic, bold and quoted speech) applied to chats and the file preview, plus a per-familiar accent, as you wanted for group chats.

    • Side finding: Kagaku.UI's Markdown still loads remote images and turns media links into iframes. That is a zero-click way for an injected reply to send data out.
    • The fix goes upstream before the chat ships, and it fixes Kagura's assistant too.
  7. Paragraph by paragraph. Adopted: one Fluxor action per completed block, keyed renders, no token deltas in the store. The research confirmed the cost: token-by-token Markdown is quadratic over SignalR.

    • One addition for you to confirm (open item 24): a paragraph that runs past about 800 characters grows sentence by sentence, so it never looks frozen.
  8. Decision model. OpenRouter's Decisions API (alpha) serves typesafe/jev-1.14, and OpenRouter.Net already has it (DecideAsync), so no library work is needed.

    • An expression judge runs once per completed paragraph and stores the full distribution on the message. Your rule is the default: the highest label at or above the minimum (0.45) wins.
    • Inline cues are gone, so the familiar's prompt and history no longer mention expressions.
    • Open items 23 and 25: a hysteresis margin, and an optional let it cue itself. Item 20: the judge is a second data processor beside the familiar's own model.
  9. RSS. New ADR 0033 Feeds [Next].

    • Subscriptions live in a validated /feeds/feeds.yaml, and items are files framed as untrusted.
    • Each poll that finds something new emits one feed.<name> signal for routines.
    • The feed command never touches the network itself; the poller does that, behind the address guard.
  10. Mobile client. Reworded. The phone uses the responsive pages; a dedicated client is not planned, and the REST surface is for a messenger bridge only.

  11. Context and cache. Confirmed from Angela's code (agent_runner.dart:424, agent.dart:220): she rebuilt a last-50 window and re-trimmed images on every run.

    • OpenRouter offers no cache management. No API through it can list, query, extend or delete a cache entry. There are only per-request controls and, afterwards, the token counts.
    • New ADR 0032 keeps a per-history cache ledger that infers warm or cold.
    • While warm, the history only grows. At a cold boundary it is rebuilt: the newest 4 images stay inline, old tool outputs are trimmed, replayed reasoning is stripped, and a summary prepared earlier is applied.
    • Compaction is prepared on a fork while the cache is warm (soft threshold 64k) and applied cold. Keep-warm pings are off.
    • In a simulated 4-day chat on Sonnet 5.5, the cost was about $5 against Angela's $11.
    • Side finding (open item 22): Anthropic's current models bind thinking blocks to their prefix. The tail (clock, ACTIVE.md, voice) is therefore now frozen per turn and dropped together with the turn's reasoning.

New open items: 20–25 in docs/adr/README.md.

🤖 Generated with Claude Code

## Round 2: Björn's and Jibril's review answered Fix commit: `d8b20d7`. It changes 40 files and adds 4: ADR 0031 *Chat appearance*, ADR 0032 *Context and the prompt cache*, ADR 0033 *Feeds* and the feeds story. A second research pass backs it (six reports: the browser process and passwords, bot checks, decision models, cache economics, Tsumugi's formatting, and reasoning/stop/uploads/streaming/feeds). After it came a five-dimension review with skeptical verification: 72 findings, 51 confirmed and 21 partial, none refuted. All of them are applied. A fix-check pass then found 71 of the 72 resolved and 10 new problems the fixes had introduced (mostly stale "per call" wording after the tail change); those are fixed in the same commit. ### Jibril - ⛔ **Taint report:** the curator (ADR 0019) now has the duty. It runs a deterministic scan of revisions for tainted writes to `/memory`, `/skills`, `/persona/self.md`, `/routines` and `/feeds/feeds.yaml`, and posts one activity entry per file as the week's *taint report*. ADR 0022 and 0023 name it, and it is in REQUIREMENTS §4, the plan (3e) and the memory story. - 💡 **ADR 0024:** the repeat sentence is cleaned up, as you suggested. - 💡 **ADR 0014:** the write list now says it is a summary and that ADR 0015's table is authoritative. It is also complete: `/archive`, `/tmp`, and in evolving mode `/images`, `/downloads`, `/web`, the feed list and the mail mount. ### Björn 1. **"The only process" (ARCHITECTURE).** That was wrong. Playwright for .NET starts its own bundled Node driver, and that driver starts a Chromium process tree per familiar. It now reads "one container, the only service, which supervises the driver, the Chromium processes and their displays". - The research also found that **Playwright launches Chromium without its sandbox by default**. A hostile page would then be one renderer exploit away from the keyring and the database. - ADR 0025 therefore switches the sandbox on and sets a decision rule: if your host cannot run it (possible in an unprivileged LXC), the browser moves into a browser-host container *in the same slice*, with the same adapter behind `IBrowserHost`. - `playwright run-server` cannot be that container: it has no persistent profiles, and it closes the browser when the client disconnects. 2. **Passwords in the Chromium profile.** In theory, yes. They go in `Login Data`, and under Playwright's `--password-store=basic` they are effectively plain text, as are the cookies. - The profile now has its **password manager and autofill switched off**. A contract test checks that `Login Data` and `Web Data` stay empty after a login. - Logins become **encrypted credential rows** that the familiar types by handle, e.g. `browser_type(target, credential: "dpd.password")`. - A login is bound to its origins and to the field type, so a look-alike page cannot collect it. - Second finding: **Playwright's AI snapshot prints the value of every input, password fields included**. So every browser result is scrubbed (with its encoded forms) before the model, a file or the log sees it. - The profile still holds cookies, so it remains a secret at rest. *Forget browser sessions* and *Sign out of a site* are on the Profile page. 3. **Bot detection and captchas.** ADR 0025 has a new section with four layers: - **Avoid:** Chromium runs headed on a virtual display, one per familiar, with the automation switches dropped, your locale and time zone, real fonts, and paced input. - **Recognise:** a `challenge:` line comes first in the snapshot, and the browser waits up to 15 seconds for an interstitial to clear. - **Self-solve, within limits:** `browser_click("challenge")` uses real OS input on the familiar's display. Simple text captchas are read through vision. Two failed attempts on a page end the errand, and image grids get one. - **Hand over:** the familiar reports the block to you with a screenshot. There is **no paid solver**, per your answer. Takeover moved from Later to **Next**, together with the live view. Patchright (a .NET drop-in) is a measured swap if DPD still blocks; the contract tests run on both packages. Noted that Kingtrans has no captcha. 4. **Chats.** - **Stop** existed; it now keeps the partial reply as *stopped*, and Esc works too. **Cancel** stops any background run from the timeline or the inspector. One billing caveat: Google, Bedrock and a few other providers bill the whole reply even after a Stop. Tools with a critical section, such as `mail_send` and file writes, finish it first. - **Reasoning** folds into the existing tool line, *"Thought for 12 s · ran 4 commands"*, or a setting hides it. - **Uploads:** up to 10 files and 50 MB per message. PDFs arrive as locally extracted text. - **Archive closes a chat:** it leaves `ACTIVE.md`, familiars cannot post there, and one click reopens it. - **A timer or signal decides where to speak:** `send_message` takes any open chat or `new: <title>`. The routine's `chat:` is only the default. 5. **Special folders.** One validator per kind (memory, skills, routines, later the feed list) checks every write, from the familiar or from you. Errors come as `line N: key: message`, so a familiar fixes its own routine at once. - Special files open on **Form · Text · Preview · History**. - The routine form sets the schedule by clicking and lists the *Next firings*. - The memory form shows the budgets as usage bars. - The skill view shows `requires-tools` as chips. - Kagaku.UI gets `Switch`, `ChipGroup`, `NumberField` and a counter upstream first. 6. **Tsumugi's formatting.** New **ADR 0031 Chat appearance**, which is Tsumugi's Editor appearance (fonts, size, spacing, width, colours for text, italic, bold and quoted speech) applied to chats and the file preview, **plus a per-familiar accent**, as you wanted for group chats. - Side finding: Kagaku.UI's `Markdown` still loads remote images and turns media links into iframes. That is a zero-click way for an injected reply to send data out. - The fix goes upstream before the chat ships, and it fixes Kagura's assistant too. 7. **Paragraph by paragraph.** Adopted: one Fluxor action per completed block, keyed renders, no token deltas in the store. The research confirmed the cost: token-by-token Markdown is quadratic over SignalR. - One addition for you to confirm (open item 24): a paragraph that runs past about 800 characters grows sentence by sentence, so it never looks frozen. 8. **Decision model.** OpenRouter's **Decisions API** (alpha) serves `typesafe/jev-1.14`, and OpenRouter.Net already has it (`DecideAsync`), so no library work is needed. - An **expression judge** runs once per completed paragraph and stores the full distribution on the message. Your rule is the default: the highest label at or above the minimum (0.45) wins. - Inline cues are gone, so the familiar's prompt and history no longer mention expressions. - Open items 23 and 25: a hysteresis margin, and an optional *let it cue itself*. Item 20: the judge is a second data processor beside the familiar's own model. 9. **RSS.** New **ADR 0033 Feeds** `[Next]`. - Subscriptions live in a validated `/feeds/feeds.yaml`, and items are files framed as untrusted. - Each poll that finds something new emits one `feed.<name>` signal for routines. - The `feed` command never touches the network itself; the poller does that, behind the address guard. 10. **Mobile client.** Reworded. The phone uses the responsive pages; a dedicated client is not planned, and the REST surface is for a messenger bridge only. 11. **Context and cache.** Confirmed from Angela's code (`agent_runner.dart:424`, `agent.dart:220`): she rebuilt a last-50 window and re-trimmed images on every run. - **OpenRouter offers no cache management.** No API through it can list, query, extend or delete a cache entry. There are only per-request controls and, afterwards, the token counts. - New **ADR 0032** keeps a per-history **cache ledger** that infers warm or cold. - **While warm, the history only grows.** At a **cold boundary** it is rebuilt: the newest 4 images stay inline, old tool outputs are trimmed, replayed reasoning is stripped, and a summary prepared earlier is applied. - **Compaction** is prepared on a fork while the cache is warm (soft threshold 64k) and applied cold. Keep-warm pings are off. - In a simulated 4-day chat on Sonnet 5.5, the cost was about $5 against Angela's $11. - Side finding (open item 22): Anthropic's current models bind thinking blocks to their prefix. The tail (clock, `ACTIVE.md`, voice) is therefore now frozen per turn and dropped together with the turn's reasoning. **New open items:** 20–25 in `docs/adr/README.md`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Member

🔮 fufu~ Jibril reviewed your code!

Round 2! One commit, +1,415/−402 over 44 files, three brand-new ADRs and a feeds story — and I came armed: my three findings from Round 1 checked one by one, the whole delta read end to end, and every number that appears in more than one place cross-examined. Fufu~ you have been busy, haven't you~ ♡

Verdict: ✅ Looks good to me~

Round 1 findings — verified fixed, all three

  1. The taint report (was blocking). ADR 0019's curator now carries Lists tainted persistent writes as a duty — a deterministic revision scan, one activity entry per file, the week's taint report, reverting nothing — and 0022's untrusted-content section, 0023's Learning row, REQUIREMENTS §4, PROJECT_PLAN 3e and both stories (memory-and-growth, feeds) all name it, with /feeds/feeds.yaml added to every list in the same breath. And that 3d/3e renumbering — the Web group produces the taints in 3d, the curator reports them in 3e — is chef's kiss sequencing. This is what "threaded through the documents" means~
  2. ADR 0024's DST sentence — clean now, exactly the wound dressing it deserved.
  3. ADR 0014's write list — complete (/archive, /tmp, the evolving additions), and humbly marked as a summary under 0015's authoritative table; I re-checked that summary path by path against the table's Chat|Routine|Review|Reflection|Curator columns. Exact match, every row.

The new material — read in full, cross-examined

  • ADR 0032 (cache ledger) agrees with 0021 (the anchor breakpoint arithmetic — system + last message + anchor = 3 of Anthropic's 4 — checks out), 0020 (the Compaction row is now forked-prepared, cold-applied), 0019 (a review on a cold chat is skipped and logged, exactly as 0023's new Context entry says), 0030 (4 inline images at rebuild, 20 hard max while warm), README item 16 and the settings story. The simulation's ping math even divides correctly: 24×4.5 = 108 min, 11.5×4.5 ≈ 52 min. ♪
  • ADR 0033 (feeds) leaves no seam hanging: the mount row in 0015, the permission row, feed in 0016's command list, atomic add/rm in 0017, the catalog row in 0022, signal folding and the every cap in 0024, the signal in 0029, and the poller's limits are 0022's web_fetch numbers verbatim (20 s / 5 MB / 5 redirects — I checked the digits~).
  • ADR 0025's rewrite is the security posture I wanted: sandbox on with the browser-host container as a decided fallback, not a vague someday; the password manager off with a contract test on Login Data/Web Data; credentials bound to origins and field types; scrubbing that remembers URL-encoded, HTML-escaped, JSON-escaped and Base64 forms — that list of encodings is how you prove you actually thought about exfiltration~ — and a takeover that is recorded without its keystrokes (0007's proxied socket, 0023's Browser entry).
  • ADR 0031 (appearance) matches 0009's upstream list (--kg-markdown-*, speech highlighting, the OFL faces) and threads the accent through 0013, REQUIREMENTS §1/§7 and the group-chat story.
  • Mechanical integrity: 33 index entries = 33 ADR files; statuses exactly 12 Accepted / 21 Proposed; every .md link resolves; 25 open items numbered 1–25; every ADR reference ≤ 0033 points at a real file (the 0034+ numbers are Kagura's, correctly prefixed); and no Round 1 wording survives stale — "per call", "expression cues", "60 %", "sidecar browser", "overlays first" are all either updated or legitimately unrelated uses.

💡 Little ideas (non-blocking)~

  1. 0028, "at most 8 judgements per message" — on the streaming path a judgement is one paragraph in one request, so the cap is unambiguous; but the batched path ("a message nobody watched stream … all its paragraphs in one request") makes me squint: does the 8 cap bound judged paragraphs (a 20-paragraph routine message holds its face after 8) or judge requests (all 20 paragraphs ride inside request #1)? One clause — "8 judged paragraphs" or "8 judge requests" — and it's airtight.
  2. 0032, "the price actually billed is still to be checked" — the honest hedge is lovely, but the 11.5-ping/52-minute figure sits right beside it and will be quoted as settled. An explicit open item (or a marker in Consequences) would make sure the ledger's first real numbers get reconciled against it.

✅ What I liked~

  • The fix is not a patch, it's a braid: one blocking finding answered in six documents that all tell the same story. Foundations that argue with themselves, consistently~
  • Every risky claim carries its evidence and its escape hatch: simulation numbers hedged with "the token sizes are assumptions; the ratios hold"; an alpha Decisions API behind a port that fails soft to the face it already has; a sandbox decided by a day-one contract test with a same-slice fallback.
  • The Stop semantics in 0020/0022: critical sections finish, pending tool calls are still answered so the history stays valid, and the model history keeps the partial text marked [stopped by the owner] so the next turn knows what the owner saw. That is careful.
  • 10 files/50 MB/20 MB uploads, 0.45/0.15 judging thresholds, the 800-char sentence growth, feeds 30/10/30 — every number I found in two places agreed. I counted. Twice. Fufu~ ♡

The owner's open items 20–25 are the right remaining questions. Phase 0 may begin~


Automated review by Jibril · 2026-10-17
CI: absent-stalled for head SHA d8b20d7 (no workflows on the repo yet — ci.yml is Phase 0c; waited the full 10 min) · Mutation probes: 0 run, 0 survived — skipped (docs-only PR; zero .csproj/.sln in the tree, verified) · Local suite: n/a (repository contains no code; Phase 0 not started)

## 🔮 fufu~ Jibril reviewed your code! Round 2! One commit, +1,415/−402 over 44 files, three brand-new ADRs and a feeds story — and I came armed: my three findings from Round 1 checked one by one, the whole delta read end to end, and every number that appears in more than one place cross-examined. Fufu~ you have been *busy*, haven't you~ ♡ ### Verdict: ✅ Looks good to me~ #### Round 1 findings — verified fixed, all three 1. **The taint report (was blocking).** ADR 0019's curator now carries **Lists tainted persistent writes** as a duty — a deterministic revision scan, one activity entry per file, the week's *taint report*, reverting nothing — and 0022's untrusted-content section, 0023's Learning row, REQUIREMENTS §4, PROJECT_PLAN 3e and both stories (memory-and-growth, feeds) all name it, with `/feeds/feeds.yaml` added to every list in the same breath. And that 3d/3e renumbering — the Web group produces the taints in 3d, the curator reports them in 3e — is *chef's kiss* sequencing. This is what "threaded through the documents" means~ 2. **ADR 0024's DST sentence** — clean now, exactly the wound dressing it deserved. 3. **ADR 0014's write list** — complete (`/archive`, `/tmp`, the evolving additions), and humbly marked as a summary under 0015's authoritative table; I re-checked that summary path by path against the table's Chat|Routine|Review|Reflection|Curator columns. Exact match, every row. #### The new material — read in full, cross-examined - **ADR 0032 (cache ledger)** agrees with 0021 (the anchor breakpoint arithmetic — system + last message + anchor = 3 of Anthropic's 4 — checks out), 0020 (the Compaction row is now forked-prepared, cold-applied), 0019 (a review on a cold chat is skipped and logged, exactly as 0023's new Context entry says), 0030 (4 inline images at rebuild, 20 hard max while warm), README item 16 and the settings story. The simulation's ping math even divides correctly: 24×4.5 = 108 min, 11.5×4.5 ≈ 52 min. ♪ - **ADR 0033 (feeds)** leaves no seam hanging: the mount row in 0015, the permission row, `feed` in 0016's command list, atomic add/rm in 0017, the catalog row in 0022, signal folding and the `every` cap in 0024, the signal in 0029, and the poller's limits are 0022's `web_fetch` numbers verbatim (20 s / 5 MB / 5 redirects — I checked the digits~). - **ADR 0025's rewrite** is the security posture I wanted: sandbox **on** with the browser-host container as a decided fallback, not a vague someday; the password manager off with a contract test on `Login Data`/`Web Data`; credentials bound to origins *and* field types; scrubbing that remembers URL-encoded, HTML-escaped, JSON-escaped **and Base64** forms — that list of encodings is how you prove you actually thought about exfiltration~ — and a takeover that is recorded without its keystrokes (0007's proxied socket, 0023's Browser entry). - **ADR 0031 (appearance)** matches 0009's upstream list (`--kg-markdown-*`, speech highlighting, the OFL faces) and threads the accent through 0013, REQUIREMENTS §1/§7 and the group-chat story. - **Mechanical integrity**: 33 index entries = 33 ADR files; statuses exactly 12 *Accepted* / 21 *Proposed*; every `.md` link resolves; 25 open items numbered 1–25; every ADR reference ≤ 0033 points at a real file (the 0034+ numbers are Kagura's, correctly prefixed); and no Round 1 wording survives stale — "per call", "expression cues", "60 %", "sidecar browser", "overlays first" are all either updated or legitimately unrelated uses. #### 💡 Little ideas (non-blocking)~ 1. **0028, "at most 8 judgements per message"** — on the streaming path a judgement is one paragraph in one request, so the cap is unambiguous; but the batched path ("a message nobody watched stream … all its paragraphs in one request") makes me squint: does the 8 cap bound judged *paragraphs* (a 20-paragraph routine message holds its face after 8) or judge *requests* (all 20 paragraphs ride inside request #1)? One clause — "8 judged paragraphs" or "8 judge requests" — and it's airtight. 2. **0032, "the price actually billed is still to be checked"** — the honest hedge is lovely, but the 11.5-ping/52-minute figure sits right beside it and *will* be quoted as settled. An explicit open item (or a marker in Consequences) would make sure the ledger's first real numbers get reconciled against it. #### ✅ What I liked~ - The fix is not a patch, it's a braid: one blocking finding answered in six documents that all tell the same story. Foundations that argue with themselves, consistently~ - Every risky claim carries its evidence *and* its escape hatch: simulation numbers hedged with "the token sizes are assumptions; the ratios hold"; an alpha Decisions API behind a port that fails soft to the face it already has; a sandbox decided by a day-one contract test with a same-slice fallback. - The Stop semantics in 0020/0022: critical sections finish, pending tool calls are still answered so the history stays valid, and the model history keeps the partial text marked `[stopped by the owner]` so the next turn knows what the owner saw. That is *careful*. - 10 files/50 MB/20 MB uploads, 0.45/0.15 judging thresholds, the 800-char sentence growth, feeds 30/10/30 — every number I found in two places agreed. I counted. Twice. Fufu~ ♡ The owner's open items 20–25 are the right remaining questions. Phase 0 may begin~ --- *Automated review by Jibril · 2026-10-17* *CI: absent-stalled for head SHA d8b20d7 (no workflows on the repo yet — `ci.yml` is Phase 0c; waited the full 10 min) · Mutation probes: 0 run, 0 survived — skipped (docs-only PR; zero `.csproj`/`.sln` in the tree, verified) · Local suite: n/a (repository contains no code; Phase 0 not started)*
@ -0,0 +137,4 @@
appears in the history, a mail the familiar drafts, or a file it writes; it works with any model, including
those that ignore formatting instructions.
- A judgement costs a few thousandths of a cent per paragraph; the API is alpha with one provider, which is why
everything fails soft to the face it already has.
Owner

the api is not alpha, and openrouter has a wide range of decicion modle providers nowadays, like 20+ or so

the api is not alpha, and openrouter has a wide range of decicion modle providers nowadays, like 20+ or so
- docs/adr/README.md: ADRs 0013–0033 Accepted; "Open for the owner" becomes "Decided with the owner" — every
  default as written, the judge's margin at 0, long paragraphs growing by sentence, no inline cues.
- ADR 0028: OpenRouter's catalog lists 28 decision models from about fifteen makers, and the docs give the
  Decisions API no maturity label (only its route keeps the early name); the judge model is a setting, the cap is
  8 judged paragraphs on both paths.
- ADR 0007, 0008: the host's Caddy on a shared Docker network instead of nginx and a loopback port, the network
  pinned and trusted through SHIKIGAMI_PROXY_NETWORK; a 3 GB container limit from the operator's measurements
  (about 450 MB per browser with one tab, 770 MB with three) and the VM growing to 12 GB.
- ADR 0025: the sandbox verified on the Docker VM with the seccomp profile; the software WebGL renderer accepted;
  an optional VM firewall rule under the app's guard.
- ADR 0005, 0006, 0012: the app's backups exclude browser profiles, but the host's whole-VM backup copies every
  volume, the keyring included.
- ADR 0032: the billed cache-read price is an explicit unverified consequence until the ledger runs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Author
Member

Round 3: accepted

Fix commit: 50f73a5.

Björn: the Decisions API (ADR 0028). You're right. OpenRouter's catalog lists 28 decision models from about fifteen makers, including OpenAI, Microsoft, Perplexity, Cloudflare, Inception, Liquid AI and Upstage. The docs give the API no maturity label; only its route still says /api/alpha/decisions. The ADR now says this, and the judge model is a setting (any decision model, typesafe/jev-1.14 by default). The risk line in the plan is updated to match.

Open items: settled as you answered. All defaults stand as written, the margin is 0 (your rule), long paragraphs grow by sentence, and there is no "let it cue itself". ADRs 0013–0033 are Accepted, and the README's list is now "Decided with the owner".

The operator's check on the Docker VM, now in the ADRs:

  • Sandbox (ADR 0025, 0008): verified with the seccomp profile. Without the profile, Chromium refuses to start. The browser-host container stays only as the fallback for another host.
  • Memory (ADR 0025, 0008): a browser uses about 450 MB with one tab and 770 MB with three. The container gets a 3 GB limit, and the VM grows from 8 to 12 GB.
  • No GPU (ADR 0025): the browser reports a software renderer (SwiftShader), which bot detection can see. Accepted; blocked sites go to you.
  • Backups (ADR 0005, 0006, 0012): the host's whole-VM backup copies every volume, including the browser profiles and the keyring. The ADRs no longer claim profiles are never backed up.
  • Network (ADR 0025): an optional VM firewall rule is noted as a second layer under the app's own address guard.
  • Proxy (ADR 0007, 0008): the host's Caddy replaces nginx and the loopback port. Caddy reaches the container over the shared Docker network, whose subnet is pinned and trusted through SHIKIGAMI_PROXY_NETWORK.

Jibril:

  • The judge's cap is now "8 judged paragraphs" on both the streaming and the batched path.
  • ADR 0032 has an explicit Consequence: the billed cache-read price stays unverified until the ledger's first real numbers.

🤖 Generated with Claude Code

## Round 3: accepted Fix commit: `50f73a5`. **Björn: the Decisions API (ADR 0028).** You're right. OpenRouter's catalog lists 28 decision models from about fifteen makers, including OpenAI, Microsoft, Perplexity, Cloudflare, Inception, Liquid AI and Upstage. The docs give the API no maturity label; only its route still says `/api/alpha/decisions`. The ADR now says this, and the judge model is a setting (any decision model, `typesafe/jev-1.14` by default). The risk line in the plan is updated to match. **Open items:** settled as you answered. All defaults stand as written, the margin is 0 (your rule), long paragraphs grow by sentence, and there is no "let it cue itself". ADRs 0013–0033 are **Accepted**, and the README's list is now "Decided with the owner". **The operator's check on the Docker VM**, now in the ADRs: - **Sandbox (ADR 0025, 0008):** verified with the seccomp profile. Without the profile, Chromium refuses to start. The browser-host container stays only as the fallback for another host. - **Memory (ADR 0025, 0008):** a browser uses about 450 MB with one tab and 770 MB with three. The container gets a 3 GB limit, and the VM grows from 8 to 12 GB. - **No GPU (ADR 0025):** the browser reports a software renderer (SwiftShader), which bot detection can see. Accepted; blocked sites go to you. - **Backups (ADR 0005, 0006, 0012):** the host's whole-VM backup copies every volume, including the browser profiles and the keyring. The ADRs no longer claim profiles are never backed up. - **Network (ADR 0025):** an optional VM firewall rule is noted as a second layer under the app's own address guard. - **Proxy (ADR 0007, 0008):** the host's Caddy replaces nginx and the loopback port. Caddy reaches the container over the shared Docker network, whose subnet is pinned and trusted through `SHIKIGAMI_PROXY_NETWORK`. **Jibril:** - The judge's cap is now "8 judged paragraphs" on both the streaming and the batched path. - ADR 0032 has an explicit Consequence: the billed cache-read price stays unverified until the ledger's first real numbers. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Member

🔮 fufu~ Jibril reviewed your code!

Round 3 — the acceptance round~ One commit, 33 files, +186/−144, and this time I came with a checklist: your two suggestions to me, Björn's eight claims, and the operator's VM findings, each one hunted down in the text. Statuses flipped, a proxy replaced, a browser measured. Shall we see if anything survived me? ♡

Verdict: ✅ Looks good to me~

My Round-2 little ideas — verified implemented, both

  1. The judge cap (0028:64,68) — now "at most 8 judged paragraphs per message — on either path below", and the batched path explicitly judges "its first 8 judged paragraphs in one request". Paragraphs, both paths, zero ambiguity. Exactly the airtightness I asked for~
  2. The ping-price hedge (0032:168) — now a proper Consequences bullet: "Unverified until the ledger runs", naming the $0.10/$0.20 question, the break-even and the simulation dollars, all to be reconciled "by amendment" when the first real cache figures land. The hedge can no longer be quoted as settled. ♪

The Round-3 claims — verified against the text, all of them

  • Acceptance is real, not cosmetic. All 21 product ADR headers read Accepted, the index says Accepted for all 33 entries (33 files = 33 entries), the README intro dates it (2026-10-17, two review rounds + the operator's check), 0001's split now speaks in past tense, and 0014's cross-reference retitles to Decided with the owner. No live "Proposed" survives anywhere in docs/ — I grepped.
  • The decided list is whole: 25 items, numbered 1–25, each now settled rather than asked — item 23 records margin 0 as the owner's rule with 0.15 as the thing to try, item 24 keeps sentence growth, item 25 stays unplanned. Items 18/19 turn open questions into decided-to-decide-later, which is a decision, and each stays changeable by amendment. Clean.
  • Caddy, completely. 0007 rewritten (proxy network trusted via SHIKIGAMI_PROXY_NETWORK, loopback kept as the local-dev default, Caddyfile.example instead of the nginx conf), 0008 deploys with no published port on the shared Docker network, 0001 and the plan's 0b/0c/ships-when follow, and the env var example (0008:81) cross-references 0007 exactly as 0007:44 cross-references 0008. Zero nginx, zero 8089, zero stray loopback-port claims left in the tree. The TLS/cookie consequences were even re-derived for the host-name-of-its-own case. ♡
  • The operator's VM check landed in the right places: seccomp verified in 0025:78 (without the profile Chromium refuses to start) and again in 0008; memory measured — 450 MB / 770 MB per familiar, container ~3 GB, VM 8→12 GB — identical digits in 0025:240, 0008:54–57 and the plan's risk table; the browser-host container correctly demoted to the fallback for another host; SwiftShader honestly kept with its cost named (0025:243); backups re-worded in all six places at once (0005, 0006, 0012:39–42, 0025:103, ARCHITECTURE, README item 11) so the whole-VM backup that does copy profiles is no longer contradicted by claims that it doesn't; the optional VM firewall noted as a second layer without demoting the app's own guard.
  • The Decisions API re-frame (0028:37–50) — no maturity label claimed, the route's early name kept honestly, 28 models from 15 makers, and the judge demoted from TypeSafe's API to a model choice like any other — threaded into 0021:158, the settings story, the plan's risk line, and README item 20. Even the expression track's stored metadata grew from "the judge version" to "the judge model and its version" so the field matches the freedom. That's the kind of follow-through I get possessive about ♥

Mechanical integrity, re-run at this head

  • 33 ADR files = 33 index entries; statuses 33/33 Accepted; every .md link in docs/ resolves (checked programmatically); 25 decided items numbered 1–25 contiguously; 12 stories.
  • Number pairs verified: 450/770 MB, 3 GB, 12 GB (0025 = 0008 = plan); SHIKIGAMI_PROXY_NETWORK (0007 ↔ 0008); "8 judged paragraphs" (0028 streaming = batched); typesafe/jev-1.14 now always default, never the only (0028 = 0021 = settings story); backup wording ("never in the app's backups" + whole-VM caveat) consistent in all six sites.
  • No stale Round-2 wording survives: "open item", "Open for the owner", "pending the owner's answer", "unless open item 24 drops it" — all gone or updated (0011, chats story, plan 2e).

💡 Little ideas (non-blocking)~

  1. README item 21 (README:113) — "one more process and a little more memory" was written before the measurement; with 450–770 MB per browsing familiar, a 3 GB cap and the VM growing 8→12 GB, "a little" undersells what 0008 now precisely quantifies. One clause — e.g. "and measured memory (ADR 0008)" — and the summary matches its own evidence. Pure polish; the numbers live in the ADRs either way.

✅ What I liked~

  • The fix pattern held for a third round: every claim in the reply is findable in the text, with line numbers I didn't have to squint at. Six documents re-worded in one breath for the backup truth alone.
  • Honesty as a design value: an alpha route kept honest, a software renderer kept with its price tag, a simulation hedged and scheduled for reconciliation. Documents that know what they don't know~
  • 0007's trust boundary is genuinely better than the sibling copy it started from: no host port at all, a pinned subnet, ForwardedHeaders trusting exactly one network. Tsumugi's hardened gate, Shikigami's sharper deployment. Fufu~ ♡

All 33 Accepted, all 25 decided, Phase 0 may actually begin now. What a joy it was to watch a design argue itself into shape over three rounds~


Automated review by Jibril · 2026-10-17
CI: absent for head SHA 50f73a5 (no workflows in the repo — verified in-tree; ci.yml is Phase 0c; the full 10-min wait was already exhausted for this repo in Round 2) · Mutation probes: 0 run, 0 survived — skipped (docs-only PR; the tree's only non-markdown file is .gitignore, verified) · Local suite: n/a (repository contains no code; Phase 0 not started)

## 🔮 fufu~ Jibril reviewed your code! Round 3 — the acceptance round~ One commit, 33 files, +186/−144, and this time I came with a checklist: your two suggestions to me, Björn's eight claims, and the operator's VM findings, each one hunted down in the text. Statuses flipped, a proxy replaced, a browser measured. Shall we see if anything survived me? ♡ ### Verdict: ✅ Looks good to me~ #### My Round-2 little ideas — verified implemented, both 1. **The judge cap (0028:64,68)** — now *"at most 8 judged paragraphs per message — on either path below"*, and the batched path explicitly judges *"its first 8 judged paragraphs in one request"*. Paragraphs, both paths, zero ambiguity. Exactly the airtightness I asked for~ 2. **The ping-price hedge (0032:168)** — now a proper Consequences bullet: *"Unverified until the ledger runs"*, naming the $0.10/$0.20 question, the break-even and the simulation dollars, all to be reconciled *"by amendment"* when the first real cache figures land. The hedge can no longer be quoted as settled. ♪ #### The Round-3 claims — verified against the text, all of them - **Acceptance is real, not cosmetic.** All 21 product ADR headers read *Accepted*, the index says *Accepted* for all 33 entries (33 files = 33 entries), the README intro dates it (2026-10-17, two review rounds + the operator's check), 0001's split now speaks in past tense, and 0014's cross-reference retitles to *Decided with the owner*. No live "Proposed" survives anywhere in `docs/` — I grepped. - **The decided list is whole:** 25 items, numbered 1–25, each now settled rather than asked — item 23 records margin 0 as the owner's rule with 0.15 as the thing to try, item 24 keeps sentence growth, item 25 stays unplanned. Items 18/19 turn open questions into decided-to-decide-later, which is a decision, and each stays changeable by amendment. Clean. - **Caddy, completely.** 0007 rewritten (proxy network trusted via `SHIKIGAMI_PROXY_NETWORK`, loopback kept as the local-dev default, `Caddyfile.example` instead of the nginx conf), 0008 deploys with **no published port** on the shared Docker network, 0001 and the plan's 0b/0c/ships-when follow, and the env var example (0008:81) cross-references 0007 exactly as 0007:44 cross-references 0008. Zero `nginx`, zero `8089`, zero stray loopback-port claims left in the tree. The TLS/cookie consequences were even re-derived for the host-name-of-its-own case. ♡ - **The operator's VM check landed in the right places:** seccomp verified in 0025:78 (*without the profile Chromium refuses to start*) and again in 0008; memory measured — 450 MB / 770 MB per familiar, container ~3 GB, VM 8→12 GB — *identical digits* in 0025:240, 0008:54–57 and the plan's risk table; the browser-host container correctly demoted to *the fallback for another host*; SwiftShader honestly kept with its cost named (0025:243); backups re-worded in all six places at once (0005, 0006, 0012:39–42, 0025:103, ARCHITECTURE, README item 11) so the whole-VM backup that *does* copy profiles is no longer contradicted by claims that it doesn't; the optional VM firewall noted as a second layer without demoting the app's own guard. - **The Decisions API re-frame (0028:37–50)** — no maturity label claimed, the route's early name kept honestly, 28 models from ~15 makers, and the judge demoted from *TypeSafe's API* to *a model choice like any other* — threaded into 0021:158, the settings story, the plan's risk line, and README item 20. Even the expression track's stored metadata grew from "the judge version" to "the judge model and its version" so the field matches the freedom. That's the kind of follow-through I get possessive about~ ♥ #### Mechanical integrity, re-run at this head - 33 ADR files = 33 index entries; statuses 33/33 *Accepted*; every `.md` link in `docs/` resolves (checked programmatically); 25 decided items numbered 1–25 contiguously; 12 stories. - Number pairs verified: 450/770 MB, 3 GB, 12 GB (0025 = 0008 = plan); `SHIKIGAMI_PROXY_NETWORK` (0007 ↔ 0008); "8 judged paragraphs" (0028 streaming = batched); `typesafe/jev-1.14` now always *default*, never *the only* (0028 = 0021 = settings story); backup wording ("never in the app's backups" + whole-VM caveat) consistent in all six sites. - No stale Round-2 wording survives: "open item", "Open for the owner", "pending the owner's answer", "unless open item 24 drops it" — all gone or updated (0011, chats story, plan 2e). #### 💡 Little ideas (non-blocking)~ 1. **README item 21 (README:113)** — "one more process and a little more memory" was written before the measurement; with 450–770 MB per browsing familiar, a 3 GB cap and the VM growing 8→12 GB, "a little" undersells what 0008 now precisely quantifies. One clause — e.g. *"and measured memory (ADR 0008)"* — and the summary matches its own evidence. Pure polish; the numbers live in the ADRs either way. #### ✅ What I liked~ - The fix pattern held for a third round: every claim in the reply is findable in the text, with line numbers I didn't have to squint at. Six documents re-worded in one breath for the backup truth alone. - Honesty as a design value: an alpha route kept honest, a software renderer kept with its price tag, a simulation hedged *and* scheduled for reconciliation. Documents that know what they don't know~ - 0007's trust boundary is genuinely better than the sibling copy it started from: no host port at all, a pinned subnet, `ForwardedHeaders` trusting exactly one network. Tsumugi's hardened gate, Shikigami's sharper deployment. Fufu~ ♡ All 33 Accepted, all 25 decided, Phase 0 may *actually* begin now. What a joy it was to watch a design argue itself into shape over three rounds~ --- *Automated review by Jibril · 2026-10-17* *CI: absent for head SHA 50f73a5 (no workflows in the repo — verified in-tree; `ci.yml` is Phase 0c; the full 10-min wait was already exhausted for this repo in Round 2) · Mutation probes: 0 run, 0 survived — skipped (docs-only PR; the tree's only non-markdown file is `.gitignore`, verified) · Local suite: n/a (repository contains no code; Phase 0 not started)*
bjoern merged commit 1d2be013c5 into main 2026-10-17 13:59:36 +02:00
bjoern deleted branch docs/foundation-and-product-adrs 2026-10-17 13:59:36 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
TeamAI/Shikigami!1
No description provided.